Statistiques
| Révision :

root / pobysoPythonSage / src / pobyso.py @ 277

Historique | Voir | Annoter | Télécharger (89,48 ko)

1
"""
2
@file pobyso.py
3
Actual functions to use in Sage
4
@author S.T. 
5
@date 2012-11-13
6

7
Command line syntax:
8
  use from Sage (via the "load" or the "attach" commands)
9

10
pobyso functions come in five flavors: 
11
- the _so_so (arguments and returned objects are pointers to Sollya objects, 
12
  includes the void function and the no arguments function that return a 
13
  pointer to a Sollya object);
14
- the _so_sa (argument are pointers to Sollya objects, returned objects are
15
  Sage/Python objects or, more generally, information is transfered from the
16
  Sollya world to Sage/Python world; e.g. functions without arguments that
17
  return a Sage/Python object);
18
- the _sa_so (arguments are Sage/Python objects, returned objects are 
19
  pointers to Sollya objects);
20
- the sa_sa (arguments and returned objects are all Sage/Python objects);
21
- a catch all flavor, without any suffix, (e. g. functions that have no 
22
  argument nor return value).
23

24
This classification is not always very strict. Conversion functions from Sollya
25
to Sage/Python are sometimes decorated with Sage/Python arguments to set
26
the precision. These functions remain in the so_sa category.
27

28
@note
29
Reported errors in Eclipse come from the calls to the Sollya library
30

31
ToDo (among other things): 
32
 -memory management.
33
"""
34
from ctypes import *
35
import re
36
from sage.symbolic.expression_conversions import polynomial
37
from sage.symbolic.expression_conversions import PolynomialConverter
38
"""
39
Create the equivalent to an enum for the Sollya function types.
40
"""
41
(SOLLYA_BASE_FUNC_ABS,
42
SOLLYA_BASE_FUNC_ACOS,
43
    SOLLYA_BASE_FUNC_ACOSH,
44
    SOLLYA_BASE_FUNC_ADD,
45
    SOLLYA_BASE_FUNC_ASIN,
46
    SOLLYA_BASE_FUNC_ASINH,
47
    SOLLYA_BASE_FUNC_ATAN,
48
    SOLLYA_BASE_FUNC_ATANH,
49
    SOLLYA_BASE_FUNC_CEIL,
50
    SOLLYA_BASE_FUNC_CONSTANT,
51
    SOLLYA_BASE_FUNC_COS,
52
    SOLLYA_BASE_FUNC_COSH,
53
    SOLLYA_BASE_FUNC_DIV,
54
    SOLLYA_BASE_FUNC_DOUBLE,
55
    SOLLYA_BASE_FUNC_DOUBLEDOUBLE,
56
    SOLLYA_BASE_FUNC_DOUBLEEXTENDED,
57
    SOLLYA_BASE_FUNC_ERF,
58
    SOLLYA_BASE_FUNC_ERFC,
59
    SOLLYA_BASE_FUNC_EXP,
60
    SOLLYA_BASE_FUNC_EXP_M1,
61
    SOLLYA_BASE_FUNC_FLOOR,
62
    SOLLYA_BASE_FUNC_FREE_VARIABLE,
63
    SOLLYA_BASE_FUNC_HALFPRECISION,
64
    SOLLYA_BASE_FUNC_LIBRARYCONSTANT,
65
    SOLLYA_BASE_FUNC_LIBRARYFUNCTION,
66
    SOLLYA_BASE_FUNC_LOG,
67
    SOLLYA_BASE_FUNC_LOG_10,
68
    SOLLYA_BASE_FUNC_LOG_1P,
69
    SOLLYA_BASE_FUNC_LOG_2,
70
    SOLLYA_BASE_FUNC_MUL,
71
    SOLLYA_BASE_FUNC_NEARESTINT,
72
    SOLLYA_BASE_FUNC_NEG,
73
    SOLLYA_BASE_FUNC_PI,
74
    SOLLYA_BASE_FUNC_POW,
75
    SOLLYA_BASE_FUNC_PROCEDUREFUNCTION,
76
    SOLLYA_BASE_FUNC_QUAD,
77
    SOLLYA_BASE_FUNC_SIN,
78
    SOLLYA_BASE_FUNC_SINGLE,
79
    SOLLYA_BASE_FUNC_SINH,
80
    SOLLYA_BASE_FUNC_SQRT,
81
    SOLLYA_BASE_FUNC_SUB,
82
    SOLLYA_BASE_FUNC_TAN,
83
    SOLLYA_BASE_FUNC_TANH,
84
SOLLYA_BASE_FUNC_TRIPLEDOUBLE) = map(int,xrange(44))
85
sys.stderr.write("Superficial pobyso check...\n")
86
#print "First constant - SOLLYA_BASE_FUNC_ABS: ", SOLLYA_BASE_FUNC_ABS
87
#print "Last constant  - SOLLYA_BASE_FUNC_TRIPLEDOUBLE: ", SOLLYA_BASE_FUNC_TRIPLEDOUBLE
88

    
89
pobyso_max_arity = 9
90

    
91
def pobyso_absolute_so_so():
92
    """
93
    Create an "absolute" Sollya object.
94
    """
95
    return(sollya_lib_absolute(None))
96

    
97
def pobyso_autoprint(arg):
98
    sollya_lib_autoprint(arg, None)
99

    
100
def pobyso_autoprint_so_so(arg):
101
    sollya_lib_autoprint(arg,None)
102
    
103
def pobyso_bounds_to_range_sa_so(rnLowerBoundSa, rnUpperBoundSa, \
104
                                 precisionSa=None):
105
    """
106
    Return a Sollya range from to 2 RealField Sage elements.
107
    The Sollya range element has a sufficient precision to hold all
108
    the digits of the widest of the Sage bounds.
109
    """
110
    # Sanity check.
111
    if rnLowerBoundSa > rnUpperBoundSa:
112
        return None
113
    # Precision stuff.
114
    if precisionSa is None:
115
        # Check for the largest precision.
116
        lbPrecSa = rnLowerBoundSa.parent().precision()
117
        ubPrecSa = rnLowerBoundSa.parent().precision()
118
        maxPrecSa = max(lbPrecSa, ubPrecSa)
119
    else:
120
        maxPrecSa = precisionSa
121
    # From Sage to Sollya bounds.
122
#    lowerBoundSo = sollya_lib_constant(get_rn_value(rnLowerBoundSa),
123
#                                       maxPrecSa)
124
    lowerBoundSo = pobyso_constant_sa_so(rnLowerBoundSa,
125
                                         maxPrecSa)
126
    upperBoundSo = pobyso_constant_sa_so(rnUpperBoundSa,
127
                                       maxPrecSa)
128
    
129
    # From Sollya bounds to range.
130
    rangeSo = sollya_lib_range(lowerBoundSo, upperBoundSo)
131
    # Back to original precision.
132
    # Clean up
133
    sollya_lib_clear_obj(lowerBoundSo)
134
    sollya_lib_clear_obj(upperBoundSo)
135
    return rangeSo
136
# End pobyso_bounds_to_range_sa_so
137

    
138
def pobyso_build_end_elliptic_list_so_so(*args):
139
    """
140
    From Sollya argument objects, create a Sollya end elliptic list.
141
    Elements of the list are "eaten" (should not be cleared individually, 
142
    are cleared when the list is cleared).
143
    """
144
    if len(args) == 0:
145
        ## Called with an empty list produced "error".
146
        return sollya_lib_build_end_elliptic_list(None)
147
    index = 0
148
    ## One can not append elements to an elliptic list, prepend only is 
149
    #  permitted.
150
    for argument in reversed(args):
151
        if index == 0:
152
            listSo = sollya_lib_build_end_elliptic_list(argument, None)
153
        else:
154
            listSo = sollya_lib_prepend(argument, listSo)
155
        index += 1
156
    return listSo
157
        
158
# End pobyso_build_end_elliptic_list_so_so
159

    
160
def pobyso_build_function_sub_so_so(exp1So, exp2So):
161
    return sollya_lib_build_function_sub(exp1So, exp2So)
162

    
163
def pobyso_build_list_of_ints_sa_so(*args):
164
    """
165
    Build a Sollya list from Sage integral arguments. 
166
    """
167
    if len(args) == 0:
168
        return pobyso_build_list_so_so()
169
    ## Make a Sage list of integral constants.
170
    intsList = []
171
    for intElem in args:
172
        intsList.append(pobyso_constant_from_int_sa_so(intElem))
173
    return pobyso_build_list_so_so(*intsList) 
174
    
175
def pobyso_build_list_so_so(*args):
176
    """
177
    Make a Sollya list out of Sollya objects passed as arguments.
178
    If one wants to call it with a list argument, should prepend a "*"
179
    before the list variable name.
180
    Elements of the list are "eaten" (should not be cleared individually, 
181
    are cleared when the list is cleared).
182
    """
183
    if len(args) == 0:
184
        ## Called with an empty list produced "error".
185
        return sollya_lib_build_list(None)
186
    index = 0
187
    ## Append the Sollya elements one by one.
188
    for elementSo in args:
189
        if index == 0:
190
            listSo = sollya_lib_build_list(elementSo, None)
191
        else:
192
            listSo = sollya_lib_append(listSo, elementSo)
193
        index += 1
194
    return listSo
195
# End pobyso_build list_so_so
196
    
197

    
198
def pobyso_change_var_in_function_so_so(funcSo, chvarExpSo):
199
    """
200
    Variable change in a function.
201
    """
202
    return(sollya_lib_evaluate(funcSo,chvarExpSo))
203
# End pobyso_change_var_in_function_so_so     
204

    
205
def pobyso_chebyshevform_so_so(functionSo, degreeSo, intervalSo):
206
    resultSo = sollya_lib_chebyshevform(functionSo, degreeSo, intervalSo)
207
    return(resultSo)
208
# End pobyso_chebyshevform_so_so.
209

    
210
def pobyso_clear_obj(objSo):
211
    """
212
    Free a Sollya object's memory.
213
    Very thin wrapper around sollya_lib_clear_obj().
214
    """
215
    sollya_lib_clear_obj(objSo)
216
# End pobyso_clear_obj. 
217

    
218
def pobyso_clear_taylorform_sa_so(taylorFormSaSo):
219
    """
220
    This method is necessary to correctly clean up the memory from Taylor forms.
221
    These are made of a Sollya object, a Sollya object list, a Sollya object.
222
    For no clearly understood reason, sollya_lib_clear_object_list crashed 
223
    when applied to the object list.
224
    Here, we decompose it into Sage list of Sollya objects references and we
225
     clear them one at a time. 
226
    """
227
    sollya_lib_clear_obj(taylorFormSaSo[0])
228
    (coefficientsErrorsListSaSo, numElementsSa, isEndEllipticSa) = \
229
        pobyso_get_list_elements_so_so(taylorFormSaSo[1])
230
    for element in coefficientsErrorsListSaSo:
231
        sollya_lib_clear_obj(element)
232
    sollya_lib_clear_obj(taylorFormSaSo[1])
233
    sollya_lib_clear_obj(taylorFormSaSo[2])
234
# End pobyso_clear_taylorform_sa_so 
235

    
236
def pobyso_cmp(rnArgSa, cteSo):
237
    """
238
    Deprecated, use pobyso_cmp_sa_so_sa instead.
239
    """
240
    print "Deprecated, use pobyso_cmp_sa_so_sa instead."
241
    return pobyso_cmp_sa_so_sa(rnArgSa, cteSo)
242
# End  pobyso_cmp
243
    
244
def pobyso_cmp_sa_so_sa(rnArgSa, cteSo):
245
    """
246
    Compare the MPFR value a RealNumber with that of a Sollya constant.
247
    
248
    Get the value of the Sollya constant into a RealNumber and compare
249
    using MPFR. Could be optimized by working directly with a mpfr_t
250
    for the intermediate number. 
251
    """
252
    # Get the precision of the Sollya constant to build a Sage RealNumber 
253
    # with enough precision.to hold it.
254
    precisionOfCte = c_int(0)
255
    # From the Sollya constant, create a local Sage RealNumber.
256
    sollya_lib_get_prec_of_constant(precisionOfCte, cteSo) 
257
    #print "Precision of constant: ", precisionOfCte
258
    RRRR = RealField(precisionOfCte.value)
259
    rnLocalSa = RRRR(0)
260
    sollya_lib_get_constant(get_rn_value(rnLocalSa), cteSo)
261
    #
262
    ## Compare the Sage RealNumber version of the Sollya constant with rnArg
263
    #  through a direct comparison of underlying MPFR numbers.
264
    return cmp_rn_value(rnArgSa, rnLocal)
265
# End pobyso_smp_sa_so_sa
266

    
267
def pobyso_compute_pos_function_abs_val_bounds_sa_sa(funcSa, lowerBoundSa, \
268
                                                     upperBoundSa):
269
    """
270
    TODO: completely rework and test.
271
    """
272
    pobyso = pobyso_name_free_variable_sa_so(funcSa.variables()[0])
273
    funcSo = pobyso_parse_string(funcSa._assume_str().replace('_SAGE_VAR_', ''))
274
    rangeSo = pobyso_range_sa_so(lowerBoundSa, upperBoundSa)
275
    infnormSo = pobyso_infnorm_so_so(funcSo,rangeSo)
276
    # Sollya return the infnorm as an interval.
277
    fMaxSa = pobyso_get_interval_from_range_so_sa(infnormSo)
278
    # Get the top bound and compute the binade top limit.
279
    fMaxUpperBoundSa = fMaxSa.upper()
280
    binadeTopLimitSa = 2**ceil(fMaxUpperBoundSa.log2())
281
    # Put up together the function to use to compute the lower bound.
282
    funcAuxSo = pobyso_parse_string(str(binadeTopLimitSa) +  \
283
                                    '-(' + f._assume_str().replace('_SAGE_VAR_', '') + ')')
284
    pobyso_autoprint(funcAuxSo)
285
    # Clear the Sollya range before a new call to infnorm and issue the call.
286
    sollya_lib_clear_obj(infnormSo)
287
    infnormSo = pobyso_infnorm_so_so(funcAuxSo,rangeSo)
288
    fMinSa = pobyso_get_interval_from_range_so_sa(infnormSo)
289
    sollya_lib_clear_obj(infnormSo)
290
    fMinLowerBoundSa = binadeTopLimitSa - fMinSa.lower()
291
    # Compute the maximum of the precisions of the different bounds.
292
    maxPrecSa = max([fMinLowerBoundSa.parent().precision(), \
293
                     fMaxUpperBoundSa.parent().precision()])
294
    # Create a RealIntervalField and create an interval with the "good" bounds.
295
    RRRI = RealIntervalField(maxPrecSa)
296
    imageIntervalSa = RRRI(fMinLowerBoundSa, fMaxUpperBoundSa)
297
    # Free the unneeded Sollya objects
298
    sollya_lib_clear_obj(funcSo)
299
    sollya_lib_clear_obj(funcAuxSo)
300
    sollya_lib_clear_obj(rangeSo)
301
    return(imageIntervalSa)
302
# End pobyso_compute_pos_function_abs_val_bounds_sa_sa
303

    
304
def pobyso_compute_precision_decay_ratio_function_sa_so():
305
    """
306
    Compute the precision decay ratio function for polynomial 
307
    coefficient progressive trucation.
308
    """
309
    functionText = """
310
    proc(deg, a, b, we, wq) 
311
    {
312
      k = we * (exp(x/a)-1) + wq * (b*x)^2 + (1-we-wq) * x;
313
      return k/k(d);
314
    };
315
    """
316
    return pobyso_parse_string_sa_so(functionText)
317
# End  pobyso_compute_precision_decay_ratio_function.
318

    
319

    
320
def pobyso_constant(rnArg):
321
    """ Legacy function. See pobyso_constant_sa_so. """
322
    return(pobyso_constant_sa_so(rnArg))
323
    
324
def pobyso_constant_sa_so(rnArgSa, precisionSa=None):
325
    """
326
    Create a Sollya constant from a Sage RealNumber.
327
    The sollya_lib_constant() function creates a constant
328
    with the same precision as the source.
329
    """
330
    ## Precision stuff. If one wants to change precisions,
331
    #  everything takes place in Sage. That only makes
332
    #  sense if one wants to reduce the precision.
333
    # TODO: revisit precision stuff with new technique.
334
    if not precisionSa is None:
335
        RRR = RealField(precisionSa)
336
        rnArgSa = RRR(rnArgSa)
337
    #print rnArgSa, rnArgSa.precision()
338
    # Sollya constant creation takes place here.
339
    return sollya_lib_constant(get_rn_value(rnArgSa))
340
# End pobyso_constant_sa_so
341
     
342
def pobyso_constant_0_sa_so():
343
    """
344
    Obvious.
345
    """
346
    return pobyso_constant_from_int_sa_so(0)
347

    
348
def pobyso_constant_1():
349
    """
350
    Obvious.
351
    Legacy function. See pobyso_constant_so_so. 
352
    """
353
    return pobyso_constant_1_sa_so()
354

    
355
def pobyso_constant_1_sa_so():
356
    """
357
    Obvious.
358
    """
359
    return(pobyso_constant_from_int_sa_so(1))
360

    
361
def pobyso_constant_from_int(anInt):
362
    """ Legacy function. See pobyso_constant_from_int_sa_so. """
363
    return pobyso_constant_from_int_sa_so(anInt)
364

    
365
def pobyso_constant_from_int_sa_so(anInt):
366
    """
367
    Get a Sollya constant from a Sage int.
368
    """
369
    return sollya_lib_constant_from_int64(long(anInt))
370

    
371
def pobyso_constant_from_int_so_sa(constSo):
372
    """
373
    Get a Sage int from a Sollya int constant.
374
    Usefull for precision or powers in polynomials.
375
    """
376
    constSa = c_long(0)
377
    sollya_lib_get_constant_as_int64(byref(constSa), constSo)
378
    return constSa.value
379
# End pobyso_constant_from_int_so_sa
380

    
381
def pobyso_constant_from_mpq_sa_so(rationalSa):
382
    """
383
    Make a Sollya constant from Sage rational.
384
    The Sollya constant is an unevaluated expression.
385
    Hence no precision argument is needed.
386
    It is better to leave this way since Sollya has its own
387
    optimized evaluation mecanism that tries very hard to
388
    return exact values or at least faithful ones.
389
    """
390
    ratExprSo = \
391
        sollya_lib_constant_from_mpq(sgmp_get_rational_value(rationalSa))
392
    return ratExprSo
393
# End pobyso_constant_from_mpq_sa_so.
394

    
395
def pobyso_constant_sollya_prec_sa_so(rnArgSa):
396
    """
397
    Create a Sollya constant from a Sage RealNumber at the
398
    current precision in Sollya.
399
    """
400
    currentSollyaPrecSa = pobyso_get_prec_so_sa()
401
    return pobyso_constant_sa_so(rnArgSa, currentSollyaPrecSa)
402
# End pobyso_constant_sollya_prec_sa_so
403

    
404
def pobyso_end_elliptic_list_so_sa_so(objectsListSo, intCountSa):
405
    """
406
    Create a Sollya end elliptic list made of the objectListSo[0] to
407
     objectsListSo[intCountSa-1] objects.
408
    """     
409
    return sollya_lib_end_elliptic_list(objectSo, int(intCountSa))
410

    
411
def pobyso_error_so():
412
    return sollya_lib_error(None)
413
# End pobyso_error().
414

    
415
def pobyso_evaluate_so_sa(funcSo, argumentSo):
416
    """
417
    Evaluates funcSo for arguemntSo through sollya_lib_evaluate() and return
418
    the result as a Sage object
419
    """
420
    evalSo = sollya_lib_evaluate(funcSo, argumentSo)
421
    if pobyso_is_error_so_sa(evalSo):
422
        return None
423
    if pobyso_is_range_so_sa(evalSo):
424
        retVal = pobyso_range_to_interval_so_sa(evalSo)
425
    else:
426
        retVal = pobyso_get_constant_as_rn(evalSo)
427
    sollya_lib_clear_obj(evalSo)
428
    return retVal
429
# End pobyso_evaluate_so_sa.
430

    
431
def pobyso_evaluate_so_so(funcSo, argumentSo):
432
    """
433
    Evaluates funcSo for arguemntSo through sollya_lib_evaluate().
434
    """
435
    return sollya_lib_evaluate(funcSo, argumentSo)
436
# End pobyso_evaluate_so_so.
437
#
438
def pobyso_diff_so_so(funcSo):
439
    """
440
    Very thin wrapper around sollya_lib_diff.
441
    """
442
    ## TODO: add a check to make sure funcSo is a functional expression.
443
    return sollya_lib_diff(funcSo)
444

    
445
def pobyso_dirty_find_zeros_so_so(funcSo, rangeSo):
446
    """
447
    Thin wrapper over sollya_lib_dirtyfindzeros()
448
    """
449
    return sollya_lib_dirtyfindzeros(funcSo, rangeSo)
450
# End pobys_dirty_find_zeros
451

    
452
def pobyso_dirty_inf_norm_so_so(funcSo, rangeSo, preSo=None):
453
    """
454
    Thin wrapper around sollya_dirtyinfnorm().
455
    """
456
    # TODO: manage the precision change.
457
    
458
    return sollya_lib_dirtyinfnorm(funcSo, rangeSo)
459
# End pobyso_dirty_inf_norm_so_so
460

    
461
def pobyso_find_zeros_so_so(funcSo, rangeSo):
462
    """
463
    Thin wrapper over sollya_lib_findzeros()
464
    """
465
    return sollya_lib_findzeros(funcSo, rangeSo)
466
# End pobys_find_zeros
467

    
468
def pobyso_float_list_so_sa(listSo):
469
    """
470
    Return a Sollya list of floating-point numbers as a Sage list of 
471
    floating-point numbers.
472
    TODO: add a test to make sure that each element of the list is a constant.
473
    """
474
    listSa   = []
475
    ## The function returns none if the list is empty or an error has happened.
476
    retVal = pobyso_get_list_elements_so_so(listSo)
477
    if retVal is None:
478
        return listSa
479
    ## Just in case the interface is changed and an empty list is returned 
480
    #  instead of None.
481
    elif len(retVal) == 0:
482
        return listSa
483
    else:
484
        ## Remember pobyso_get_list_elements_so_so returns more information
485
        #  than just the elements of the list (# elements, is_elliptic)
486
        listSaSo, numElements, isEndElliptic = retVal
487
    ## Return an empty list.
488
    if numElements == 0:
489
        return listSa
490
    ## Search first for the maximum precision of the elements
491
    maxPrecSa = 0
492
    for floatSo in listSaSo:
493
        #pobyso_autoprint(floatSo)
494
        curPrecSa =  pobyso_get_prec_of_constant_so_sa(floatSo)
495
        if curPrecSa > maxPrecSa:
496
            maxPrecSa = curPrecSa
497
    ##
498
    RF = RealField(maxPrecSa)
499
    ##
500
    for floatSo in listSaSo:
501
        listSa.append(pobyso_get_constant_as_rn_with_rf_so_sa(floatSo))
502
    return listSa
503
# End pobyso_float_list_so_sa
504

    
505
def pobyso_float_poly_sa_so(polySa, precSa = None):
506
    """
507
    Create a Sollya polynomial from a Sage RealField polynomial.
508
    """
509
    ## TODO: filter arguments.
510
    ## Precision. If a precision is given, convert the polynomial
511
    #  into the right polynomial field. If not convert it straight
512
    #  to Sollya.
513
    sollyaPrecChanged = False 
514
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
515
    if precSa is None:
516
        precSa = polySa.parent().base_ring().precision()
517
    if (precSa > initialSollyaPrecSa):
518
        assert precSa >= 2, "Precision change <2 requested"
519
        if precSa <= 2:
520
            print inspect.stack()[0][3], ": precision change <= 2 requested"
521
        precSo = pobyso_constant_from_int(precSa)
522
        pobyso_set_prec_so_so(precSo)
523
        sollya_lib_clear_obj(precSo)
524
        sollyaPrecChanged = True
525
    ## Free variable stuff.
526
    freeVariableNameChanged = False 
527
    polyFreeVariableNameSa = \
528
        str(polySa.variables()[0])
529
    currentFreeVariableNameSa = pobyso_get_free_variable_name_so_sa() 
530
    if polyFreeVariableNameSa != currentFreeVariableNameSa:
531
        #print "Free variable names do not match.", polyFreeVariableNameSa
532
        sollya_lib_name_free_variable(polyFreeVariableNameSa)
533
        freeVariableNameChanged = True
534
    ## Get exponents and coefficients.
535
    exponentsSa     = polySa.exponents()
536
    coefficientsSa  = polySa.coefficients()
537
    ## Build the polynomial.
538
    polySo = None
539
    for coefficientSa, exponentSa in zip(coefficientsSa, exponentsSa):
540
        #print coefficientSa.n(prec=precSa), exponentSa
541
        coefficientSo = \
542
            pobyso_constant_sa_so(coefficientSa)
543
        #pobyso_autoprint(coefficientSo)
544
        exponentSo = \
545
            pobyso_constant_from_int_sa_so(exponentSa)
546
        #pobyso_autoprint(exponentSo)
547
        monomialSo = sollya_lib_build_function_pow(
548
                       sollya_lib_build_function_free_variable(),
549
                       exponentSo)
550
        polyTermSo = sollya_lib_build_function_mul(coefficientSo,
551
                                                       monomialSo)
552
        if polySo is None:
553
            polySo = polyTermSo
554
        else:
555
            polySo = sollya_lib_build_function_add(polySo, polyTermSo)
556
    if sollyaPrecChanged:
557
        pobyso_set_prec_so_so(initialSollyaPrecSo)
558
    sollya_lib_clear_obj(initialSollyaPrecSo)
559
    ## Do not set back the free variable name in Sollya to its initial value: 
560
    #  it will change it back, in the Sollya polynomial, to what it was in the 
561
    #  first place.
562
    return polySo
563
# End pobyso_float_poly_sa_so    
564

    
565
def pobyso_float_poly_so_sa(polySo, realFieldSa=None):
566
    """
567
    Convert a Sollya polynomial into a Sage floating-point polynomial.
568
    If no realField is given, a RealField corresponding to the maximum 
569
    precision of the coefficients is internally computed.
570
    The real field is not returned but can be easily retrieved from 
571
    the polynomial itself.
572
    ALGORITHM:
573
    - (optional) compute the RealField of the coefficients;
574
    - convert the Sollya expression into a Sage expression;
575
    - convert the Sage expression into a Sage polynomial
576
    """    
577
    if realFieldSa is None:
578
        expressionPrecSa = pobyso_get_max_prec_of_exp_so_sa(polySo)
579
        #print "Maximum precision of Sollya polynomial coefficients:", expressionPrecSa
580
        if expressionPrecSa < 2 or expressionPrecSa > 2147483391:
581
            print "Maximum degree of expression:", expressionPrecSa
582
        realFieldSa      = RealField(expressionPrecSa)
583
    #print "Sollya expression before...",
584
    #pobyso_autoprint(polySo)
585

    
586
    expressionSa = pobyso_get_sage_exp_from_sollya_exp_so_sa(polySo,
587
                                                             realFieldSa)
588
    #print "...Sollya expression after."
589
    #pobyso_autoprint(polySo)
590
    polyVariableSa = expressionSa.variables()[0]
591
    polyRingSa     = realFieldSa[str(polyVariableSa)]
592
    #print polyRingSa
593
    # Do not use the polynomial(expressionSa, ring=polyRingSa) form!
594
    polynomialSa = polyRingSa(expressionSa)
595
    polyCoeffsListSa = polynomialSa.coefficients()
596
    #for coeff in polyCoeffsListSa:
597
    #    print coeff.abs().n()
598
    return polynomialSa
599
# End pobyso_float_poly_so_sa
600

    
601
def pobyso_free_variable():
602
    """
603
    Ultra thin wrapper around the sollya_lib_function_build_free_variable function.
604
    """
605
    return sollya_lib_build_function_free_variable()
606
    
607
def pobyso_function_type_as_string(funcType):
608
    """ Legacy function. See pobyso_function_type_as_string_so_sa. """
609
    return(pobyso_function_type_as_string_so_sa(funcType))
610

    
611
def pobyso_function_type_as_string_so_sa(funcType):
612
    """
613
    Numeric Sollya function codes -> Sage mathematical function names.
614
    Notice that pow -> ^ (a la Sage, not a la Python).
615
    """
616
    if funcType == SOLLYA_BASE_FUNC_ABS:
617
        return "abs"
618
    elif funcType == SOLLYA_BASE_FUNC_ACOS:
619
        return "arccos"
620
    elif funcType == SOLLYA_BASE_FUNC_ACOSH:
621
        return "arccosh"
622
    elif funcType == SOLLYA_BASE_FUNC_ADD:
623
        return "+"
624
    elif funcType == SOLLYA_BASE_FUNC_ASIN:
625
        return "arcsin"
626
    elif funcType == SOLLYA_BASE_FUNC_ASINH:
627
        return "arcsinh"
628
    elif funcType == SOLLYA_BASE_FUNC_ATAN:
629
        return "arctan"
630
    elif funcType == SOLLYA_BASE_FUNC_ATANH:
631
        return "arctanh"
632
    elif funcType == SOLLYA_BASE_FUNC_CEIL:
633
        return "ceil"
634
    elif funcType == SOLLYA_BASE_FUNC_CONSTANT:
635
        return "cte"
636
    elif funcType == SOLLYA_BASE_FUNC_COS:
637
        return "cos"
638
    elif funcType == SOLLYA_BASE_FUNC_COSH:
639
        return "cosh"
640
    elif funcType == SOLLYA_BASE_FUNC_DIV:
641
        return "/"
642
    elif funcType == SOLLYA_BASE_FUNC_DOUBLE:
643
        return "double"
644
    elif funcType == SOLLYA_BASE_FUNC_DOUBLEDOUBLE:
645
        return "doubleDouble"
646
    elif funcType == SOLLYA_BASE_FUNC_DOUBLEEXTENDED:
647
        return "doubleDxtended"
648
    elif funcType == SOLLYA_BASE_FUNC_ERF:
649
        return "erf"
650
    elif funcType == SOLLYA_BASE_FUNC_ERFC:
651
        return "erfc"
652
    elif funcType == SOLLYA_BASE_FUNC_EXP:
653
        return "exp"
654
    elif funcType == SOLLYA_BASE_FUNC_EXP_M1:
655
        return "expm1"
656
    elif funcType == SOLLYA_BASE_FUNC_FLOOR:
657
        return "floor"
658
    elif funcType == SOLLYA_BASE_FUNC_FREE_VARIABLE:
659
        return "freeVariable"
660
    elif funcType == SOLLYA_BASE_FUNC_HALFPRECISION:
661
        return "halfPrecision"
662
    elif funcType == SOLLYA_BASE_FUNC_LIBRARYCONSTANT:
663
        return "libraryConstant"
664
    elif funcType == SOLLYA_BASE_FUNC_LIBRARYFUNCTION:
665
        return "libraryFunction"
666
    elif funcType == SOLLYA_BASE_FUNC_LOG:
667
        return "log"
668
    elif funcType == SOLLYA_BASE_FUNC_LOG_10:
669
        return "log10"
670
    elif funcType == SOLLYA_BASE_FUNC_LOG_1P:
671
        return "log1p"
672
    elif funcType == SOLLYA_BASE_FUNC_LOG_2:
673
        return "log2"
674
    elif funcType == SOLLYA_BASE_FUNC_MUL:
675
        return "*"
676
    elif funcType == SOLLYA_BASE_FUNC_NEARESTINT:
677
        return "round"
678
    elif funcType == SOLLYA_BASE_FUNC_NEG:
679
        return "__neg__"
680
    elif funcType == SOLLYA_BASE_FUNC_PI:
681
        return "pi"
682
    elif funcType == SOLLYA_BASE_FUNC_POW:
683
        return "^"
684
    elif funcType == SOLLYA_BASE_FUNC_PROCEDUREFUNCTION:
685
        return "procedureFunction"
686
    elif funcType == SOLLYA_BASE_FUNC_QUAD:
687
        return "quad"
688
    elif funcType == SOLLYA_BASE_FUNC_SIN:
689
        return "sin"
690
    elif funcType == SOLLYA_BASE_FUNC_SINGLE:
691
        return "single"
692
    elif funcType == SOLLYA_BASE_FUNC_SINH:
693
        return "sinh"
694
    elif funcType == SOLLYA_BASE_FUNC_SQRT:
695
        return "sqrt"
696
    elif funcType == SOLLYA_BASE_FUNC_SUB:
697
        return "-"
698
    elif funcType == SOLLYA_BASE_FUNC_TAN:
699
        return "tan"
700
    elif funcType == SOLLYA_BASE_FUNC_TANH:
701
        return "tanh"
702
    elif funcType == SOLLYA_BASE_FUNC_TRIPLEDOUBLE:
703
        return "tripleDouble"
704
    else:
705
        return None
706

    
707
def pobyso_get_constant(rnArgSa, constSo):
708
    """ Legacy function. See pobyso_get_constant_so_sa. """
709
    return pobyso_get_constant_so_sa(rnArgSa, constSo)
710
# End pobyso_get_constant
711

    
712
def pobyso_get_constant_so_sa(rnArgSa, constSo):
713
    """
714
    Set the value of rnArgSo to the value of constSo in MPFR_RNDN mode.
715
    rnArg must already exist and belong to some RealField.
716
    We assume that constSo points to a Sollya constant.
717
    """
718
    outcome = sollya_lib_get_constant(get_rn_value(rnArgSa), constSo)
719
    if outcome == 0: # Failure because constSo is not a constant expression.
720
        return None
721
    else:
722
        return outcome
723
# End  pobyso_get_constant_so_sa
724
   
725
def pobyso_get_constant_as_rn(ctExpSo):
726
    """ 
727
    Legacy function. See pobyso_get_constant_as_rn_so_sa. 
728
    """ 
729
    return(pobyso_get_constant_as_rn_so_sa(ctExpSo))
730
    
731
def pobyso_get_constant_as_rn_so_sa(constExpSo):
732
    """
733
    Get a Sollya constant as a Sage "real number".
734
    The precision of the floating-point number returned is that of the Sollya
735
    constant.
736
    """
737
    #print "Before computing precision of variable..."
738
    #pobyso_autoprint(constExpSo)
739
    precisionSa  = pobyso_get_prec_of_constant_so_sa(constExpSo)
740
    #print "precisionSa:", precisionSa
741
    ## If the expression can not be exactly converted, None is returned.
742
    #  In this case opt for the Sollya current expression.
743
    if precisionSa is None:
744
        precisionSa = pobyso_get_prec_so_sa()
745
    RRRR = RealField(precisionSa)
746
    rnSa = RRRR(0)
747
    outcome = sollya_lib_get_constant(get_rn_value(rnSa), constExpSo)
748
    if outcome == 0:
749
        return None
750
    else:
751
        return rnSa
752
# End pobyso_get_constant_as_rn_so_sa
753

    
754
def pobyso_get_constant_as_rn_with_rf(ctExp, realField):
755
    """ 
756
    Legacy function. See pobyso_get_constant_as_rn_with_rf_so_sa.
757
    """
758
    return pobyso_get_constant_as_rn_with_rf_so_sa(ctExp, realField)
759
# End pobyso_get_constant_as_rn_with_rf
760
    
761
def pobyso_get_constant_as_rn_with_rf_so_sa(ctExpSo, realFieldSa = None):
762
    """
763
    Get a Sollya constant as a Sage "real number".
764
    If no real field is specified, the precision of the floating-point number 
765
    returned is that of the Sollya constant.
766
    Otherwise is is that of the real field. Hence rounding may happen.
767
    """
768
    if realFieldSa is None:
769
        return pobyso_get_constant_as_rn_so_sa(ctExpSo)
770
    rnSa = realFieldSa(0)
771
    outcome = sollya_lib_get_constant(get_rn_value(rnSa), ctExpSo)
772
    if outcome == 0:
773
        return None
774
    else:
775
        return rnSa
776
# End pobyso_get_constant_as_rn_with_rf_so_sa
777

    
778
def pobyso_get_free_variable_name():
779
    """ 
780
    Legacy function. See pobyso_get_free_variable_name_so_sa.
781
    """
782
    return(pobyso_get_free_variable_name_so_sa())
783

    
784
def pobyso_get_free_variable_name_so_sa():
785
    return sollya_lib_get_free_variable_name()
786
    
787
def pobyso_get_function_arity(expressionSo):
788
    """ 
789
    Legacy function. See pobyso_get_function_arity_so_sa.
790
    """
791
    return(pobyso_get_function_arity_so_sa(expressionSo))
792

    
793
def pobyso_get_function_arity_so_sa(expressionSo):
794
    arity = c_int(0)
795
    sollya_lib_get_function_arity(byref(arity),expressionSo)
796
    return int(arity.value)
797

    
798
def pobyso_get_head_function(expressionSo):
799
    """ 
800
    Legacy function. See pobyso_get_head_function_so_sa. 
801
    """
802
    return(pobyso_get_head_function_so_sa(expressionSo)) 
803

    
804
def pobyso_get_head_function_so_sa(expressionSo):
805
    functionType = c_int(0)
806
    sollya_lib_get_head_function(byref(functionType), expressionSo)
807
    return int(functionType.value)
808

    
809
def pobyso_get_interval_from_range_so_sa(soRange, realIntervalFieldSa = None ):
810
    """
811
    Return the Sage interval corresponding to the Sollya range argument.
812
    If no reaIntervalField is passed as an argument, the interval bounds are not
813
    rounded: they are elements of RealIntervalField of the "right" precision
814
    to hold all the digits.
815
    """
816
    prec = c_int(0)
817
    if realIntervalFieldSa is None:
818
        retval = sollya_lib_get_prec_of_range(byref(prec), soRange, None)
819
        if retval == 0:
820
            return None
821
        realIntervalFieldSa = RealIntervalField(prec.value)
822
    intervalSa = realIntervalFieldSa(0,0)
823
    retval = \
824
        sollya_lib_get_interval_from_range(get_interval_value(intervalSa),\
825
                                           soRange)
826
    if retval == 0:
827
        return None
828
    return intervalSa
829
# End pobyso_get_interval_from_range_so_sa
830

    
831
def pobyso_get_list_elements(soObj):
832
    """ Legacy function. See pobyso_get_list_elements_so_so. """
833
    return pobyso_get_list_elements_so_so(soObj)
834
 
835
def pobyso_get_list_elements_so_so(objectListSo):
836
    """
837
    Get the Sollya list elements as a Sage/Python array of Sollya objects.
838
    
839
    INPUT:
840
    - objectListSo: a Sollya list of Sollya objects.
841
    
842
    OUTPUT:
843
    - a Sage/Python tuple made of:
844
      - a Sage/Python list of Sollya objects,
845
      - a Sage/Python int holding the number of elements,
846
      - a Sage/Python int stating (!= 0) that the list is end-elliptic.
847
    NOTE::
848
        We recover the addresses of the Sollya object from the list of pointers
849
        returned by sollya_lib_get_list_elements. The list itself is freed.
850
    TODO::
851
        Figure out what to do with numElements since the number of elements
852
        can easily be recovered from the list itself. 
853
        Ditto for isEndElliptic.
854
    """
855
    listAddress = POINTER(c_longlong)()
856
    numElements = c_int(0)
857
    isEndElliptic = c_int(0)
858
    listAsSageList = []
859
    result = sollya_lib_get_list_elements(byref(listAddress),\
860
                                          byref(numElements),\
861
                                          byref(isEndElliptic),\
862
                                          objectListSo)
863
    if result == 0 :
864
        return None
865
    for i in xrange(0, numElements.value, 1):
866
       #listAsSageList.append(sollya_lib_copy_obj(listAddress[i]))
867
       listAsSageList.append(listAddress[i])
868
       # Clear each of the elements returned by Sollya.
869
       #sollya_lib_clear_obj(listAddress[i])
870
    # Free the list itself.   
871
    sollya_lib_free(listAddress)
872
    return (listAsSageList, numElements.value, isEndElliptic.value)
873

    
874
def pobyso_get_max_prec_of_exp(soExp):
875
    """ Legacy function. See pobyso_get_max_prec_of_exp_so_sa. """
876
    return pobyso_get_max_prec_of_exp_so_sa(soExp)
877

    
878
def pobyso_get_max_prec_of_exp_so_sa(expSo):
879
    """
880
    Get the maximum precision used for the numbers in a Sollya expression.
881
    
882
    Arguments:
883
    soExp -- a Sollya expression pointer
884
    Return value:
885
    A Python integer
886
    TODO: 
887
    - error management;
888
    - correctly deal with numerical type such as DOUBLEEXTENDED.
889
    """
890
    if expSo is None:
891
        print inspect.stack()[0][3], ": expSo is None."
892
        return 0
893
    maxPrecision = 0
894
    minConstPrec = 0
895
    currentConstPrec = 0
896
    #pobyso_autoprint(expSo)
897
    operator = pobyso_get_head_function_so_sa(expSo)
898
    if (operator != SOLLYA_BASE_FUNC_CONSTANT) and \
899
    (operator != SOLLYA_BASE_FUNC_FREE_VARIABLE):
900
        (arity, subexpressions) = pobyso_get_subfunctions_so_sa(expSo)
901
        for i in xrange(arity):
902
            maxPrecisionCandidate = \
903
                pobyso_get_max_prec_of_exp_so_sa(subexpressions[i])
904
            if maxPrecisionCandidate > maxPrecision:
905
                maxPrecision = maxPrecisionCandidate
906
        return maxPrecision
907
    elif operator == SOLLYA_BASE_FUNC_CONSTANT:
908
        #minConstPrec = pobyso_get_min_prec_of_constant_so_sa(expSo)
909
        #currentConstPrec = pobyso_get_min_prec_of_constant_so_sa(soExp)
910
        #print minConstPrec, " - ", currentConstPrec 
911
        return pobyso_get_min_prec_of_constant_so_sa(expSo)
912
    
913
    elif operator == SOLLYA_BASE_FUNC_FREE_VARIABLE:
914
        return 0
915
    else:
916
        print "pobyso_get_max_prec_of_exp_so_sa: unexepected operator."
917
        return 0
918

    
919
def pobyso_get_min_prec_of_constant_so_sa(constExpSo):
920
    """
921
    Get the minimum precision necessary to represent the value of a Sollya
922
    constant.
923
    MPFR_MIN_PREC and powers of 2 are taken into account.
924
    We assume that constExpSo is a pointer to a Sollay constant expression.
925
    """
926
    constExpAsRnSa = pobyso_get_constant_as_rn_so_sa(constExpSo)
927
    return(min_mpfr_size(get_rn_value(constExpAsRnSa)))
928

    
929
def pobyso_get_poly_so_sa(polySo, realFieldSa=None):
930
    """
931
    Convert a Sollya polynomial into a Sage polynomial.
932
    Legacy function. Use pobyso_float_poly_so_sa() instead.
933
    """    
934
    return pobyso_float_poly_so_sa(polySo,realFieldSa)
935
# End pobyso_get_poly_so_sa
936

    
937
def pobyso_get_prec():
938
    """ Legacy function. See pobyso_get_prec_so_sa(). """
939
    return pobyso_get_prec_so_sa()
940

    
941
def pobyso_get_prec_so():
942
    """
943
    Get the current default precision in Sollya.
944
    The return value is a Sollya object.
945
    Usefull when modifying the precision back and forth by avoiding
946
    extra conversions.
947
    """
948
    return sollya_lib_get_prec(None)
949
    
950
def pobyso_get_prec_so_sa():
951
    """
952
    Get the current default precision in Sollya.
953
    The return value is Sage/Python int.
954
    """
955
    precSo = sollya_lib_get_prec()
956
    precSa = pobyso_constant_from_int_so_sa(precSo)
957
    sollya_lib_clear_obj(precSo)
958
    return precSa
959
# End pobyso_get_prec_so_sa.
960

    
961
def pobyso_get_prec_so_so_sa():
962
    """
963
    Return the current precision both as a Sollya object and a
964
    Sage integer as hybrid tuple.
965
    To avoid multiple calls for precision manipulations. 
966
    """
967
    precSo = sollya_lib_get_prec()
968
    precSa = pobyso_constant_from_int_so_sa(precSo)
969
    return (precSo, int(precSa))
970
    
971
def pobyso_get_prec_of_constant(ctExpSo):
972
    """ Legacy function. See pobyso_get_prec_of_constant_so_sa. """
973
    return pobyso_get_prec_of_constant_so_sa(ctExpSo)
974

    
975
def pobyso_get_prec_of_constant_so_sa(ctExpSo):
976
    """
977
    Tries to find a precision to represent ctExpSo without rounding.
978
    If not possible, returns None.
979
    """
980
    #print "Entering pobyso_get_prec_of_constant_so_sa..."
981
    prec = c_int(0)
982
    retc = sollya_lib_get_prec_of_constant(byref(prec), ctExpSo, None)
983
    if retc == 0:
984
        #print "pobyso_get_prec_of_constant_so_sa failed."
985
        return None
986
    #print "...exiting pobyso_get_prec_of_constant_so_sa."
987
    return int(prec.value)
988

    
989
def pobyso_get_prec_of_range_so_sa(rangeSo):
990
    """
991
    Returns the number of bits elements of a range are coded with.
992
    """
993
    prec = c_int(0)
994
    retc = sollya_lib_get_prec_of_range(byref(prec), rangeSo, None)
995
    if retc == 0:
996
        return(None)
997
    return int(prec.value)
998
# End pobyso_get_prec_of_range_so_sa()
999

    
1000
def pobyso_get_sage_exp_from_sollya_exp(sollyaExpSo, realField = RR):
1001
    """ Legacy function. See pobyso_get_sage_exp_from_sollya_exp_so_sa. """
1002
    return pobyso_get_sage_exp_from_sollya_exp_so_sa(sollyaExpSo, 
1003
                                                     realField = RR)
1004

    
1005
def pobyso_get_sage_exp_from_sollya_exp_so_sa(sollyaExpSo, realFieldSa = RR):
1006
    """
1007
    Get a Sage expression from a Sollya expression. 
1008
    Currently only tested with polynomials with floating-point coefficients.
1009
    Notice that, in the returned polynomial, the exponents are RealNumbers.
1010
    """
1011
    #pobyso_autoprint(sollyaExp)
1012
    operatorSa = pobyso_get_head_function_so_sa(sollyaExpSo)
1013
    sollyaLibFreeVariableName = sollya_lib_get_free_variable_name()
1014
    ## Get rid of the "_"'s in "_x_", if any.
1015
    sollyaLibFreeVariableName = re.sub('_', '', sollyaLibFreeVariableName)
1016
    # Constants and the free variable are special cases.
1017
    # All other operator are dealt with in the same way.
1018
    if (operatorSa != SOLLYA_BASE_FUNC_CONSTANT) and \
1019
       (operatorSa != SOLLYA_BASE_FUNC_FREE_VARIABLE):
1020
        (aritySa, subexpressionsSa) = pobyso_get_subfunctions_so_sa(sollyaExpSo)
1021
        if aritySa == 1:
1022
            sageExpSa = eval(pobyso_function_type_as_string_so_sa(operatorSa) + \
1023
            "(" + pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressionsSa[0], \
1024
            realFieldSa) + ")")
1025
        elif aritySa == 2:
1026
            # We do not get through the preprocessor.
1027
            # The "^" operator is then a special case.
1028
            if operatorSa == SOLLYA_BASE_FUNC_POW:
1029
                operatorAsStringSa = "**"
1030
            else:
1031
                operatorAsStringSa = \
1032
                    pobyso_function_type_as_string_so_sa(operatorSa)
1033
            sageExpSa = \
1034
              eval("pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressionsSa[0], realFieldSa)"\
1035
              + " " + operatorAsStringSa + " " + \
1036
                   "pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressionsSa[1], realFieldSa)")
1037
        # We do not know yet how to deal with arity >= 3 
1038
        # (is there any in Sollya anyway?).
1039
        else:
1040
            sageExpSa = eval('None')
1041
        return sageExpSa
1042
    elif operatorSa == SOLLYA_BASE_FUNC_CONSTANT:
1043
        #print "This is a constant"
1044
        return pobyso_get_constant_as_rn_with_rf_so_sa(sollyaExpSo, realFieldSa)
1045
    elif operatorSa == SOLLYA_BASE_FUNC_FREE_VARIABLE:
1046
        #print "This is the free variable"
1047
        return eval(sollyaLibFreeVariableName)
1048
    else:
1049
        print "Unexpected"
1050
        return eval('None')
1051
# End pobyso_get_sage_exp_from_sollya_exp_so_sa
1052

    
1053

    
1054
def pobyso_get_subfunctions(expressionSo):
1055
    """ Legacy function. See pobyso_get_subfunctions_so_sa. """
1056
    return pobyso_get_subfunctions_so_sa(expressionSo) 
1057
# End pobyso_get_subfunctions.
1058
 
1059
def pobyso_get_subfunctions_so_sa(expressionSo):
1060
    """
1061
    Get the subfunctions of an expression.
1062
    Return the number of subfunctions and the list of subfunctions addresses.
1063
    S.T.: Could not figure out another way than that ugly list of declarations
1064
    to recover the addresses of the subfunctions.
1065
    We limit ourselves to arity 8 functions. 
1066
    """
1067
    subf0 = c_int(0)
1068
    subf1 = c_int(0)
1069
    subf2 = c_int(0)
1070
    subf3 = c_int(0)
1071
    subf4 = c_int(0)
1072
    subf5 = c_int(0)
1073
    subf6 = c_int(0)
1074
    subf7 = c_int(0)
1075
    subf8 = c_int(0)
1076
    arity = c_int(0)
1077
    nullPtr = POINTER(c_int)()
1078
    sollya_lib_get_subfunctions(expressionSo, byref(arity), \
1079
      byref(subf0), byref(subf1), byref(subf2), byref(subf3), \
1080
      byref(subf4), byref(subf5),\
1081
      byref(subf6), byref(subf7), byref(subf8), nullPtr, None) 
1082
#    byref(cast(subfunctions[0], POINTER(c_int))), \
1083
#    byref(cast(subfunctions[0], POINTER(c_int))), \
1084
#    byref(cast(subfunctions[2], POINTER(c_int))), \
1085
#    byref(cast(subfunctions[3], POINTER(c_int))), \
1086
#    byref(cast(subfunctions[4], POINTER(c_int))), \
1087
#    byref(cast(subfunctions[5], POINTER(c_int))), \
1088
#    byref(cast(subfunctions[6], POINTER(c_int))), \
1089
#    byref(cast(subfunctions[7], POINTER(c_int))), \
1090
#    byref(cast(subfunctions[8], POINTER(c_int))), nullPtr)
1091
    subfunctions = [subf0, subf1, subf2, subf3, subf4, subf5, subf6, subf7, \
1092
                    subf8]
1093
    subs = []
1094
    if arity.value > pobyso_max_arity:
1095
        return(0,[])
1096
    for i in xrange(arity.value):
1097
        subs.append(int(subfunctions[i].value))
1098
        #print subs[i]
1099
    return (int(arity.value), subs)
1100
# End pobyso_get_subfunctions_so_sa
1101
    
1102
def pobyso_guess_degree_sa_sa(functionSa, intervalSa, approxErrorSa, 
1103
                              weightSa=None, degreeBoundSa=None):
1104
    """
1105
    Sa_sa variant of the solly_guessdegree function.
1106
    Return 0 if something goes wrong.
1107
    """
1108
    functionAsStringSa = functionSa._assume_str().replace('_SAGE_VAR_', '')
1109
    functionSo = pobyso_parse_string_sa_so(functionAsStringSa)
1110
    if pobyso_is_error_so_sa(functionSo):
1111
        sollya_lib_clear_obj(functionSo)
1112
        return 0
1113
    rangeSo = pobyso_interval_to_range_sa_so(intervalSa)
1114
    # The approximation error is expected to be a floating point number.
1115
    if pobyso_is_floating_point_number_sa_sa(approxErrorSa):
1116
        approxErrorSo = pobyso_constant_sa_so(approxErrorSa)
1117
    else:
1118
        approxErrorSo = pobyso_constant_sa_so(RR(approxErrorSa))
1119
    if not weightSa is None:
1120
        weightAsStringSa = weightSa._assume_str().replace('_SAGE_VAR_', '')
1121
        weightSo = pobyso_parse_string_sa_so(weightAsStringSa)
1122
        if pobyso_is_error_so_sa(weightSo):
1123
            sollya_lib_clear_obj(functionSo)
1124
            sollya_lib_clear_obj(rangeSo)
1125
            sollya_lib_clear_obj(approxErrorSo)   
1126
            sollya_lib_clear_obj(weightSo)
1127
            return 0   
1128
    else:
1129
        weightSo = None
1130
    if not degreeBoundSa is None:
1131
        degreeBoundSo = pobyso_constant_from_int_sa_so(degreeBoundSa)
1132
    else:
1133
        degreeBoundSo = None
1134
    guessedDegreeSa = pobyso_guess_degree_so_sa(functionSo,
1135
                                                rangeSo,
1136
                                                approxErrorSo,
1137
                                                weightSo,
1138
                                                degreeBoundSo)
1139
    sollya_lib_clear_obj(functionSo)
1140
    sollya_lib_clear_obj(rangeSo)
1141
    sollya_lib_clear_obj(approxErrorSo)
1142
    if not weightSo is None:
1143
        sollya_lib_clear_obj(weightSo)
1144
    if not degreeBoundSo is None:
1145
        sollya_lib_clear_obj(degreeBoundSo)
1146
    return guessedDegreeSa
1147
# End poyso_guess_degree_sa_sa
1148

    
1149
def pobyso_guess_degree_so_sa(functionSo, rangeSo, errorSo, weightSo=None, \
1150
                              degreeBoundSo=None):
1151
    """
1152
    Thin wrapper around the guessdegree function.
1153
    Nevertheless, some precision control stuff has been appended.
1154
    """
1155
    # Deal with Sollya internal precision issues: if it is too small, 
1156
    # compared with the error, increases it to about twice -log2(error).
1157
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(errorSo)
1158
    log2ErrorSa = errorSa.log2()
1159
    if log2ErrorSa < 0:
1160
        neededPrecisionSa = int(2 * int(-log2ErrorSa) / 64) * 64
1161
    else:
1162
        neededPrecisionSa = int(2 * int(log2ErrorSa) / 64) * 64
1163
    #print "Needed precision:", neededPrecisionSa
1164
    sollyaPrecisionHasChanged = False
1165
    (initialPrecSo, initialPrecSa) = pobyso_get_prec_so_so_sa()
1166
    if neededPrecisionSa > initialPrecSa:
1167
        if neededPrecisionSa <= 2:
1168
            print inspect.stack()[0][3], ": precision change <= 2 requested."
1169
        pobyso_set_prec_sa_so(neededPrecisionSa)
1170
        sollyaPrecisionHasChanged = True
1171
    #print "Guessing degree..."
1172
    # weightSo and degreeBoundsSo are optional arguments.
1173
    # As declared, sollya_lib_guessdegree must take 5 arguments.
1174
    if weightSo is None:
1175
        degreeRangeSo = sollya_lib_guessdegree(functionSo, rangeSo, errorSo, 
1176
                                               0, 0, None)
1177
    elif degreeBoundSo is None:
1178
        degreeRangeSo =  sollya_lib_guessdegree(functionSo, rangeSo, \
1179
                                                errorSo, weightSo, 0, None)
1180
    else:
1181
        degreeRangeSo =  sollya_lib_guessdegree(functionSo, rangeSo, errorSo, \
1182
                                                weightSo, degreeBoundSo, None)
1183
    #print "...degree guess done."
1184
    # Restore internal precision, if applicable.
1185
    if sollyaPrecisionHasChanged:
1186
        pobyso_set_prec_so_so(initialPrecSo)
1187
        sollya_lib_clear_obj(initialPrecSo)
1188
    degreeIntervalSa = pobyso_range_to_interval_so_sa(degreeRangeSo)
1189
    sollya_lib_clear_obj(degreeRangeSo)
1190
    # When ok, both bounds match.
1191
    # When the degree bound is too low, the upper bound is the degree
1192
    # for which the error can be honored.
1193
    # When it really goes wrong, the upper bound is infinity. 
1194
    if degreeIntervalSa.lower() == degreeIntervalSa.upper():
1195
        return int(degreeIntervalSa.lower())
1196
    else:
1197
        if degreeIntervalSa.upper().is_infinity():
1198
            return None
1199
        else:
1200
            return int(degreeIntervalSa.upper())
1201
    # End pobyso_guess_degree_so_sa
1202

    
1203
def pobyso_inf_so_so(intervalSo):
1204
    """
1205
    Very thin wrapper around sollya_lib_inf().
1206
    """
1207
    return sollya_lib_inf(intervalSo)
1208
# End pobyso_inf_so_so.
1209
    
1210
def pobyso_infnorm_so_so(func, interval, file = None, intervalList = None):
1211
    print "Do not use this function. User pobyso_supnorm_so_so instead."
1212
    return None
1213

    
1214
def pobyso_interval_to_range_sa_so(intervalSa, precisionSa=None):
1215
    if precisionSa is None:
1216
        precisionSa = intervalSa.parent().precision()
1217
    intervalSo = pobyso_bounds_to_range_sa_so(intervalSa.lower(),\
1218
                                              intervalSa.upper(),\
1219
                                              precisionSa)
1220
    return intervalSo
1221
# End pobyso_interval_to_range_sa_so
1222

    
1223
def pobyso_is_error_so_sa(objSo):
1224
    """
1225
    Thin wrapper around the sollya_lib_obj_is_error() function.
1226
    """
1227
    if sollya_lib_obj_is_error(objSo) != 0:
1228
        return True
1229
    else:
1230
        return False
1231
# End pobyso_is_error-so_sa
1232

    
1233
def pobyso_is_floating_point_number_sa_sa(numberSa):
1234
    """
1235
    Check whether a Sage number is floating point.
1236
    Exception stuff added because numbers other than
1237
    floating-point ones do not have the is_real() attribute.
1238
    """
1239
    try:
1240
        return numberSa.is_real()
1241
    except AttributeError:
1242
        return False
1243
# End pobyso_is_floating_piont_number_sa_sa
1244

    
1245
def pobyso_is_range_so_sa(rangeCandidateSo):
1246
    """
1247
    Thin wrapper over sollya_lib_is_range.
1248
    """
1249
    return sollya_lib_obj_is_range(rangeCandidateSo) != 0
1250
    
1251
# End pobyso_is_range_so_sa
1252

    
1253

    
1254
def pobyso_lib_init():
1255
    sollya_lib_init(None)
1256

    
1257
def pobyso_lib_close():
1258
    sollya_lib_close(None)
1259

    
1260
def pobyso_name_free_variable(freeVariableNameSa):
1261
    """ Legacy function. See pobyso_name_free_variable_sa_so. """
1262
    pobyso_name_free_variable_sa_so(freeVariableNameSa)
1263

    
1264
def pobyso_name_free_variable_sa_so(freeVariableNameSa):
1265
    """
1266
    Set the free variable name in Sollya from a Sage string.
1267
    """
1268
    sollya_lib_name_free_variable(freeVariableNameSa)
1269

    
1270
def pobyso_parse_string(string):
1271
    """ Legacy function. See pobyso_parse_string_sa_so. """
1272
    return pobyso_parse_string_sa_so(string)
1273
 
1274
def pobyso_parse_string_sa_so(string):
1275
    """
1276
    Get the Sollya expression computed from a Sage string or
1277
    a Sollya error object if parsing failed.
1278
    """
1279
    return sollya_lib_parse_string(string)
1280

    
1281
def pobyso_precision_so_sa(ctExpSo):
1282
    """
1283
    Computes the necessary precision to represent a number.
1284
    If x is not zero, it can be uniquely written as x = m · 2e 
1285
    where m is an odd integer and e is an integer. 
1286
    precision(x) returns the number of bits necessary to write m 
1287
    in binary (i.e. ceil(log2(m))).
1288
    """
1289
    #TODO: take care of the special case: 0, @NaN@, @Inf@
1290
    precisionSo = sollya_lib_precision(ctExpSo)
1291
    precisionSa = pobyso_constant_from_int_so_sa(precisionSo)
1292
    sollya_lib_clear_obj(precisionSo)
1293
    return precisionSa
1294
# End pobyso_precision_so_sa
1295

    
1296
def pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
1297
                                                           funcSo,
1298
                                                           icSo,
1299
                                                           intervalSo,
1300
                                                           itpSo,
1301
                                                           ftpSo,
1302
                                                           maxPrecSo,
1303
                                                           maxErrSo,
1304
                                                           debug=False):
1305
    if debug:
1306
        print "Input arguments:"
1307
        pobyso_autoprint(polySo)
1308
        pobyso_autoprint(funcSo)
1309
        pobyso_autoprint(icSo)
1310
        pobyso_autoprint(intervalSo)
1311
        pobyso_autoprint(itpSo)
1312
        pobyso_autoprint(ftpSo)
1313
        pobyso_autoprint(maxPrecSo)
1314
        pobyso_autoprint(maxErrSo)
1315
        print "________________"
1316
    
1317
    ## Higher order function see: 
1318
    #  http://effbot.org/pyfaq/how-do-you-make-a-higher-order-function-in-python.htm
1319
    def precision_decay_ratio_function(degreeSa):
1320
        def outer(x):
1321
            def inner(x):
1322
                we = 3/8
1323
                wq = 2/8
1324
                a  = 2.2
1325
                b  = 2 
1326
                return we*(exp(x/a)-1) +  wq*((b*x)**2) + (1-we-wq)*x
1327
            return  inner(x)/inner(degreeSa)
1328
        return outer
1329
    
1330
    #
1331
    degreeSa        = pobyso_polynomial_degree_so_sa(polySo)
1332
    ratio           = precision_decay_ratio_function(degreeSa)
1333
    itpSa           = pobyso_constant_from_int_so_sa(itpSo)
1334
    ftpSa           = pobyso_constant_from_int_so_sa(ftpSo)
1335
    maxPrecSa       = pobyso_constant_from_int_so_sa(maxPrecSo)
1336
    maxErrSa        = pobyso_get_constant_as_rn_so_sa(maxErrSo)
1337
    if debug:
1338
        print "degreeSa:", degreeSa
1339
        print "ratio:", ratio
1340
        print "itpsSa:", itpSa
1341
        print "ftpSa:", ftpSa
1342
        print "maxPrecSa:", maxPrecSa
1343
        print "maxErrSa:", maxErrSa
1344
    lastResPolySo   = None
1345
    lastInfNormSo   = None
1346
    #print "About to enter the while loop..."
1347
    while True: 
1348
        resPolySo   = pobyso_constant_0_sa_so()
1349
        pDeltaSa    = ftpSa - itpSa
1350
        for indexSa in reversed(xrange(0,degreeSa+1)):
1351
            #print "Index:", indexSa
1352
            indexSo = pobyso_constant_from_int_sa_so(indexSa)
1353
            #pobyso_autoprint(indexSo)
1354
            #print ratio(indexSa)
1355
            ctpSa = floor(ftpSa - (pDeltaSa * ratio(indexSa)))
1356
            ctpSo = pobyso_constant_from_int_sa_so(ctpSa)
1357
            if debug:
1358
                print "Index:", indexSa, " - Target precision:", 
1359
                pobyso_autoprint(ctpSo)
1360
            cmonSo  = \
1361
                sollya_lib_build_function_mul(sollya_lib_coeff(polySo, indexSo),
1362
                                      sollya_lib_build_function_pow( \
1363
                                          sollya_lib_build_function_free_variable(), \
1364
                                          indexSo))
1365
            #pobyso_autoprint(cmonSo)
1366
            cmonrSo = pobyso_round_coefficients_single_so_so(cmonSo, ctpSo)
1367
            sollya_lib_clear_obj(cmonSo)
1368
            #pobyso_autoprint(cmonrSo)
1369
            resPolySo = sollya_lib_build_function_add(resPolySo,
1370
                                                      cmonrSo)
1371
            #pobyso_autoprint(resPolySo)
1372
        # End for index
1373
        freeVarSo     = sollya_lib_build_function_free_variable()
1374
        changeVarSo   = sollya_lib_sub(freeVarSo, icSo)
1375
        resPolyCvSo   = sollya_lib_evaluate(resPolySo, changeVarSo)
1376
        errFuncSo = sollya_lib_build_function_sub(sollya_lib_copy_obj(funcSo), 
1377
                                                  resPolyCvSo)
1378
        infNormSo = sollya_lib_dirtyinfnorm(errFuncSo, intervalSo)
1379
        cerrSa    = pobyso_get_constant_as_rn_so_sa(infNormSo)
1380
        if debug:
1381
            print "Infnorm (Sollya):", 
1382
            pobyso_autoprint(infNormSo)
1383
        sollya_lib_clear_obj(errFuncSo)
1384
        #print "Infnorm  (Sage):", cerrSa
1385
        if (cerrSa > maxErrSa):
1386
            if debug:
1387
                print "Error is too large."
1388
            if lastResPolySo is None:
1389
                if debug:
1390
                    print "Enlarging prec."
1391
                ntpSa = floor(ftpSa + ftpSa/50)
1392
                ## Can't enlarge (numerical)
1393
                if ntpSa == ftpSa:
1394
                    sollya_lib_clear_obj(resPolySo)
1395
                    return None
1396
                ## Can't enlarge (not enough precision left)
1397
                if ntpSa > maxPrecSa:
1398
                    sollya_lib_clear_obj(resPolySo)
1399
                    return None
1400
                ftpSa = ntpSa
1401
                continue
1402
            ## One enlargement took place.
1403
            else:
1404
                if debug:
1405
                    print "Exit with the last before last polynomial."
1406
                    print "Precision of highest degree monomial:", itpSa
1407
                    print "Precision of constant term          :", ftpSa
1408
                sollya_lib_clear_obj(resPolySo)
1409
                sollya_lib_clear_obj(infNormSo)
1410
                return (lastResPolySo, lastInfNormSo)
1411
        # cerrSa <= maxErrSa: scrap more bits, possibly.
1412
        else:
1413
            if debug:
1414
                print "Error is too small"
1415
            if cerrSa <= (maxErrSa/2):
1416
                if debug: 
1417
                    print "Shrinking prec."
1418
                ntpSa = floor(ftpSa - ftpSa/50)
1419
                ## Can't shrink (numerical)
1420
                if ntpSa == ftpSa:
1421
                    if not lastResPolySo is None:
1422
                        sollya_lib_clear_obj(lastResPolySo)
1423
                    if not lastInfNormSo is None:
1424
                        sollya_lib_clear_obj(lastInfNormSo)
1425
                    if debug:
1426
                        print "Exit because can't shrink anymore (numerically)."
1427
                        print "Precision of highest degree monomial:", itpSa
1428
                        print "Precision of constant term          :", ftpSa
1429
                    return (resPolySo, infNormSo)
1430
                ## Can't shrink (not enough precision left)
1431
                if ntpSa <= itpSa:
1432
                    if not lastResPolySo is None:
1433
                        sollya_lib_clear_obj(lastResPolySo)
1434
                    if not lastInfNormSo is None:
1435
                        sollya_lib_clear_obj(lastInfNormSo)
1436
                        print "Exit because can't shrink anymore (no bits left)."
1437
                        print "Precision of highest degree monomial:", itpSa
1438
                        print "Precision of constant term          :", ftpSa
1439
                    return (resPolySo, infNormSo)
1440
                ftpSa = ntpSa
1441
                if not lastResPolySo is None:
1442
                    sollya_lib_clear_obj(lastResPolySo)
1443
                if not lastInfNormSo is None:
1444
                    sollya_lib_clear_obj(lastInfNormSo)
1445
                lastResPolySo = resPolySo
1446
                lastInfNormSo = infNormSo
1447
                continue
1448
            else: # Error is not that small, just return
1449
                if not lastResPolySo is None:
1450
                    sollya_lib_clear_obj(lastResPolySo)
1451
                if not lastInfNormSo is None:
1452
                    sollya_lib_clear_obj(lastInfNormSo)
1453
                if debug:
1454
                    print "Exit normally."
1455
                    print "Precision of highest degree monomial:", itpSa
1456
                    print "Precision of constant term          :", ftpSa
1457
                return (resPolySo, infNormSo)                
1458
    # End wile True
1459
    return None
1460
# End pobyso_polynomial_coefficients_progressive_truncate_so_so.
1461

    
1462
def pobyso_polynomial_degree_so_sa(polySo):
1463
    """
1464
    Return the degree of a Sollya polynomial as a Sage int.
1465
    """
1466
    degreeSo = sollya_lib_degree(polySo)
1467
    return pobyso_constant_from_int_so_sa(degreeSo)
1468
# End pobyso_polynomial_degree_so_sa
1469

    
1470
def pobyso_polynomial_degree_so_so(polySo):
1471
    """
1472
    Thin wrapper around lib_sollya_degree().
1473
    """
1474
    return sollya_lib_degree(polySo)
1475
# End pobyso_polynomial_degree_so_so
1476
                                                                  
1477
def pobyso_range(rnLowerBound, rnUpperBound):
1478
    """ Legacy function. See pobyso_range_sa_so. """
1479
    return pobyso_range_sa_so(rnLowerBound, rnUpperBound) 
1480

    
1481
def pobyso_range_from_bounds_sa_so(rnLowerBound, rnUpperBound, precSa = None):
1482
    """
1483
    Create a Sollya range from 2 Sage real numbers as bounds
1484
    """
1485
    # TODO check precision stuff.
1486
    sollyaPrecChanged = False
1487
    (initialSollyaPrecSo, initialSollyaPrecSa) = \
1488
        pobyso_get_prec_so_so_sa()
1489
    if precSa is None:
1490
        precSa = max(rnLowerBound.parent().prec(), rnUpperBound.parent().prec())
1491
    if precSa > initialSollyaPrecSa:
1492
        if precSa <= 2:
1493
            print inspect.stack()[0][3], ": precision change <= 2 requested."
1494
        pobyso_set_prec_sa_so(precSa)
1495
        sollyaPrecChanged = True
1496
    rangeSo = sollya_lib_range_from_bounds(get_rn_value(rnLowerBound),
1497
                                           get_rn_value(rnUpperBound))
1498
    if sollyaPrecChanged:
1499
        pobyso_set_prec_so_so(initialSollyaPrecSo)
1500
        sollya_lib_clear_obj(initialSollyaPrecSo)
1501
    return rangeSo
1502
# End pobyso_range_from_bounds_sa_so
1503

    
1504
def pobyso_range_list_so_sa(listSo):
1505
    """
1506
    Return a Sollya list of ranges as a Sage list of 
1507
    floating-point intervals.
1508
    """
1509
    listSa   = []
1510
    ## The function returns none if the list is empty or an error has happened.
1511
    retVal = pobyso_get_list_elements_so_so(listSo)
1512
    if retVal is None:
1513
        return listSa
1514
    ## Just in case the interface is changed and an empty list is returned 
1515
    #  instead of None.
1516
    elif len(retVal) == 0:
1517
        return listSa
1518
    else:
1519
        ## Remember pobyso_get_list_elements_so_so returns more information
1520
        #  than just the elements of the list (# elements, is_elliptic)
1521
        listSaSo, numElements, isEndElliptic = retVal
1522
    ## Return an empty list.
1523
    if numElements == 0:
1524
        return listSa
1525
    ## Search first for the maximum precision of the elements
1526
    maxPrecSa = 0
1527
    for rangeSo in listSaSo:
1528
        #pobyso_autoprint(floatSo)
1529
        curPrecSa =  pobyso_get_prec_of_range_so_sa(rangeSo)
1530
        if curPrecSa > maxPrecSa:
1531
            maxPrecSa = curPrecSa
1532
    ##
1533
    intervalField = RealIntervalField(maxPrecSa)
1534
    ##
1535
    for rangeSo in listSaSo:
1536
        listSa.append(pobyso_range_to_interval_so_sa(rangeSo, intervalField))
1537
    return listSa
1538
# End pobyso_range_list_so_sa
1539

    
1540
def pobyso_range_max_abs_so_so(rangeSo):
1541
    """
1542
    Return, as Sollya constant, the maximum absolute value of a Sollay range.
1543
    """
1544
    lowerBoundSo = sollya_lib_inf(rangeSo)
1545
    upperBoundSo = sollya_lib_sup(rangeSo)
1546
    #
1547
    lowerBoundSo = sollya_lib_build_function_abs(lowerBoundSo)
1548
    upperBoundSo = sollya_lib_build_function_abs(upperBoundSo)
1549
    #pobyso_autoprint(lowerBoundSo)
1550
    #pobyso_autoprint(upperBoundSo)
1551
    #
1552
    maxAbsSo = sollya_lib_max(lowerBoundSo, upperBoundSo, None)
1553
    #sollya_lib_clear_obj(lowerBoundSo)
1554
    #sollya_lib_clear_obj(upperBoundSo)
1555
    return maxAbsSo
1556
# End pobyso_range_max_abs_so_so
1557
 
1558
def pobyso_range_to_interval_so_sa(rangeSo, realIntervalFieldSa = None):
1559
    """
1560
    Get a Sage interval from a Sollya range.
1561
    If no realIntervalField is given as a parameter, the Sage interval
1562
    precision is that of the Sollya range.
1563
    Otherwise, the precision is that of the realIntervalField. In this case
1564
    rounding may happen.
1565
    """
1566
    if realIntervalFieldSa is None:
1567
        precSa = pobyso_get_prec_of_range_so_sa(rangeSo)
1568
        realIntervalFieldSa = RealIntervalField(precSa)
1569
    intervalSa = \
1570
        pobyso_get_interval_from_range_so_sa(rangeSo, realIntervalFieldSa) 
1571
    return intervalSa
1572
# End pobyso_range_to_interval_so_sa
1573
#
1574
def pobyso_relative_so_so():
1575
    """
1576
    Very thin wrapper around the sollya_lib_relative function.
1577
    """
1578
    return sollya_lib_relative()
1579
# End pobyso_relative_so_so
1580
#
1581
def pobyso_rat_poly_sa_so(polySa, precSa = None):
1582
    """
1583
    Create a Sollya polynomial from a Sage rational polynomial.
1584
    We first convert the rational polynomial into a floating-point 
1585
    polynomial.
1586
    """
1587
    ## TODO: filter arguments.
1588
    ## Precision. If no precision is given, use the current precision
1589
    #  of Sollya.
1590
    if precSa is None:
1591
        precSa =  pobyso_get_prec_so_sa()
1592
    #print "Precision:",  precSa
1593
    RRR = RealField(precSa)
1594
    ## Create a Sage polynomial in the "right" precision.
1595
    P_RRR = RRR[polySa.variables()[0]]
1596
    polyFloatSa = P_RRR(polySa)
1597
    ## Make sure no precision is provided: pobyso_float_poly_sa_so will
1598
    #  recover it all by itself and will not make any extra conversion.
1599
    return pobyso_float_poly_sa_so(polyFloatSa)
1600
    
1601
# End pobyso_rat_poly_sa_so    
1602
    
1603
def pobyso_remez_canonical_sa_sa(func, \
1604
                                 degree, \
1605
                                 lowerBound, \
1606
                                 upperBound, \
1607
                                 weight = None, \
1608
                                 quality = None):
1609
    """
1610
    All arguments are Sage/Python.
1611
    The functions (func and weight) must be passed as expressions or strings.
1612
    Otherwise the function fails. 
1613
    The return value is a Sage polynomial.
1614
    """
1615
    var('zorglub')    # Dummy variable name for type check only. Type of 
1616
    # zorglub is "symbolic expression".
1617
    polySo = pobyso_remez_canonical_sa_so(func, \
1618
                                 degree, \
1619
                                 lowerBound, \
1620
                                 upperBound, \
1621
                                 weight, \
1622
                                 quality)
1623
    # String test
1624
    if parent(func) == parent("string"):
1625
        functionSa = eval(func)
1626
    # Expression test.
1627
    elif type(func) == type(zorglub):
1628
        functionSa = func
1629
    else:
1630
        return None
1631
    #
1632
    maxPrecision = 0
1633
    if polySo is None:
1634
        return(None)
1635
    maxPrecision = pobyso_get_max_prec_of_exp_so_sa(polySo)
1636
    RRRRSa = RealField(maxPrecision)
1637
    polynomialRingSa = RRRRSa[functionSa.variables()[0]]
1638
    expSa = pobyso_get_sage_exp_from_sollya_exp_so_sa(polySo, RRRRSa)
1639
    polySa = polynomial(expSa, polynomialRingSa)
1640
    sollya_lib_clear_obj(polySo)
1641
    return(polySa)
1642
# End pobyso_remez_canonical_sa_sa
1643
    
1644
def pobyso_remez_canonical(func, \
1645
                           degree, \
1646
                           lowerBound, \
1647
                           upperBound, \
1648
                           weight = "1", \
1649
                           quality = None):
1650
    """ Legacy function. See pobyso_remez_canonical_sa_so. """
1651
    return(pobyso_remez_canonical_sa_so(func, \
1652
                                        degree, \
1653
                                        lowerBound, \
1654
                                        upperBound, \
1655
                                        weight, \
1656
                                        quality))
1657
# End pobyso_remez_canonical.
1658

    
1659
def pobyso_remez_canonical_sa_so(func, \
1660
                                 degree, \
1661
                                 lowerBound, \
1662
                                 upperBound, \
1663
                                 weight = None, \
1664
                                 quality = None):
1665
    """
1666
    All arguments are Sage/Python.
1667
    The functions (func and weight) must be passed as expressions or strings.
1668
    Otherwise the function fails. 
1669
    The return value is a pointer to a Sollya function.
1670
    lowerBound and upperBound mus be reals.
1671
    """
1672
    var('zorglub')    # Dummy variable name for type check only. Type of
1673
    # zorglub is "symbolic expression".
1674
    currentVariableNameSa = None
1675
    # The func argument can be of different types (string, 
1676
    # symbolic expression...)
1677
    if parent(func) == parent("string"):
1678
        localFuncSa = sage_eval(func,globals())
1679
        if len(localFuncSa.variables()) > 0:
1680
            currentVariableNameSa = localFuncSa.variables()[0]
1681
            sollya_lib_name_free_variable(str(currentVariableNameSa))
1682
            functionSo = \
1683
              sollya_lib_parse_string(localFuncSa._assume_str().replace('_SAGE_VAR_', ''))
1684
    # Expression test.
1685
    elif type(func) == type(zorglub):
1686
        # Until we are able to translate Sage expressions into Sollya 
1687
        # expressions : parse the string version.
1688
        if len(func.variables()) > 0:
1689
            currentVariableNameSa = func.variables()[0]
1690
            sollya_lib_name_free_variable(str(currentVariableNameSa))
1691
            functionSo = \
1692
              sollya_lib_parse_string(func._assume_str().replace('_SAGE_VAR_', ''))
1693
    else:
1694
        return(None)
1695
    if weight is None: # No weight given -> 1.
1696
        weightSo = pobyso_constant_1_sa_so()
1697
    elif parent(weight) == parent("string"): # Weight given as string: parse it.
1698
        weightSo = sollya_lib_parse_string(func)
1699
    elif type(weight) == type(zorglub): # Weight given as symbolice expression.
1700
        functionSo = \
1701
          sollya_lib_parse_string_sa_so(weight._assume_str().replace('_SAGE_VAR_', ''))
1702
    else:
1703
        return(None)
1704
    degreeSo = pobyso_constant_from_int(degree)
1705
    rangeSo = pobyso_bounds_to_range_sa_so(lowerBound, upperBound)
1706
    if not quality is None:
1707
        qualitySo= pobyso_constant_sa_so(quality)
1708
    else:
1709
        qualitySo = None
1710
        
1711
    remezPolySo = sollya_lib_remez(functionSo, \
1712
                                   degreeSo, \
1713
                                   rangeSo, \
1714
                                   weightSo, \
1715
                                   qualitySo, \
1716
                                   None)
1717
    sollya_lib_clear_obj(functionSo)
1718
    sollya_lib_clear_obj(degreeSo)
1719
    sollya_lib_clear_obj(rangeSo)
1720
    sollya_lib_clear_obj(weightSo)
1721
    if not qualitySo is None:
1722
        sollya_lib_clear_obj(qualitySo)
1723
    return(remezPolySo)
1724
# End pobyso_remez_canonical_sa_so
1725

    
1726
def pobyso_remez_canonical_so_so(funcSo, \
1727
                                 degreeSo, \
1728
                                 rangeSo, \
1729
                                 weightSo = pobyso_constant_1_sa_so(),\
1730
                                 qualitySo = None):
1731
    """
1732
    All arguments are pointers to Sollya objects.
1733
    The return value is a pointer to a Sollya function.
1734
    """
1735
    if not sollya_lib_obj_is_function(funcSo):
1736
        return(None)
1737
    return(sollya_lib_remez(funcSo, degreeSo, rangeSo, weightSo, qualitySo, None))
1738
# End pobyso_remez_canonical_so_so.
1739

    
1740
def pobyso_remez_exponents_list_sa_so(func,     \
1741
                                 exponentsList, \
1742
                                 lowerBound,    \
1743
                                 upperBound,    \
1744
                                 weight = None, \
1745
                                 quality = None):
1746
    """
1747
    All arguments are Sage/Python.
1748
    The functions (func and weight) must be passed as expressions or strings.
1749
    Otherwise the function fails. 
1750
    The return value is a pointer to a Sollya function.
1751
    lowerBound and upperBound mus be reals.
1752
    """
1753
    var('zorglub')    # Dummy variable name for type check only. Type of
1754
    # zorglub is "symbolic expression".
1755
    currentVariableNameSa = None
1756
    # The func argument can be of different types (string, 
1757
    # symbolic expression...)
1758
    if parent(func) == parent("string"):
1759
        localFuncSa = sage_eval(func,globals())
1760
        if len(localFuncSa.variables()) > 0:
1761
            currentVariableNameSa = localFuncSa.variables()[0]
1762
            sollya_lib_name_free_variable(str(currentVariableNameSa))
1763
            functionSo = \
1764
              sollya_lib_parse_string(localFuncSa._assume_str().replace('_SAGE_VAR_', ''))
1765
    # Expression test.
1766
    elif type(func) == type(zorglub):
1767
        # Until we are able to translate Sage expressions into Sollya 
1768
        # expressions : parse the string version.
1769
        if len(func.variables()) > 0:
1770
            currentVariableNameSa = func.variables()[0]
1771
            sollya_lib_name_free_variable(str(currentVariableNameSa))
1772
            functionSo = \
1773
              sollya_lib_parse_string(func._assume_str().replace('_SAGE_VAR_', ''))
1774
    else:
1775
        return(None)
1776
    ## Deal with the weight, much in the same way as with the function.
1777
    if weight is None: # No weight given -> 1.
1778
        weightSo = pobyso_constant_1_sa_so()
1779
    elif parent(weight) == parent("string"): # Weight given as string: parse it.
1780
        weightSo = sollya_lib_parse_string(func)
1781
    elif type(weight) == type(zorglub): # Weight given as symbolice expression.
1782
        functionSo = \
1783
          sollya_lib_parse_string(weight._assume_str().replace('_SAGE_VAR_', '',100))
1784
    else:
1785
        return(None)
1786
    rangeSo = pobyso_bounds_to_range_sa_so(lowerBound, upperBound)
1787
    if not quality is None:
1788
        qualitySo= pobyso_constant_sa_so(quality)
1789
    else:
1790
        qualitySo = None
1791
    #
1792
    ## Tranform the Sage list of exponents into a Sollya list.
1793
    exponentsListSo = pobyso_build_list_of_ints_sa_so(*exponentsList)
1794
    remezPolySo = sollya_lib_remez(functionSo, \
1795
                                   exponentsListSo, \
1796
                                   rangeSo, \
1797
                                   weightSo, \
1798
                                   qualitySo, \
1799
                                   None)
1800
    sollya_lib_clear_obj(functionSo)
1801
    sollya_lib_clear_obj(exponentsListSo)
1802
    sollya_lib_clear_obj(rangeSo)
1803
    sollya_lib_clear_obj(weightSo)
1804
    if not qualitySo is None:
1805
        sollya_lib_clear_obj(qualitySo)
1806
    return(remezPolySo)
1807
# End pobyso_remez_exponentsList_sa_so
1808
#
1809
def pobyso_round_coefficients_so_so(polySo, truncFormatListSo):
1810
    """
1811
    A wrapper around the "classical" sollya_lib_roundcoefficients: a Sollya
1812
    polynomial and a Sollya list are given as arguments.
1813
    """
1814
    return sollya_lib_roundcoefficients(polySo, truncFormatListSo)
1815

    
1816
def pobyso_round_coefficients_progressive_so_so(polySo, 
1817
                                                funcSo,
1818
                                                precSo,
1819
                                                intervalSo,
1820
                                                icSo,
1821
                                                currentApproxErrorSo,
1822
                                                approxAccurSo,
1823
                                                debug=False):
1824
    """
1825
    From an input approximation polynomial, compute an output one with 
1826
    smaller coefficients and yet yields a sufficient approximation accuracy.
1827
    """
1828
    if debug:
1829
        print "Input arguments:"
1830
        print "Polynomial: ", ; pobyso_autoprint(polySo)
1831
        print "Function: ", ; pobyso_autoprint(funcSo)
1832
        print "Internal precision: ", ; pobyso_autoprint(precSo)
1833
        print "Interval: ", ; pobyso_autoprint(intervalSo)
1834
        print "Current approximation error: ", ; pobyso_autoprint(currentApproxErrorSo)
1835
        print "Requested approxiation error: ", ; pobyso_autoprint(approxAccurSo)
1836
        print "________________"
1837
    approxAccurSa        = pobyso_get_constant_as_rn_so_sa(approxAccurSo)
1838
    currentApproxErrorSa = pobyso_get_constant_as_rn_so_sa(currentApproxErrorSo)
1839
    ## If the current approximation error is too close to the target, there is
1840
    #  no possible gain.
1841
    if currentApproxErrorSa >= approxAccurSa / 2:
1842
        #### Do not return the initial argument but copies: caller may free 
1843
        #    the former as inutile after call.
1844
        return (sollya_lib_copy_obj(polySo),
1845
                sollya_lib_copy_obj(currentApproxErrorSo))
1846
    degreeSa             = pobyso_polynomial_degree_so_sa(polySo)
1847
    intervalSa           = pobyso_range_to_interval_so_sa(intervalSo)
1848
    
1849
    if debug:
1850
        print "degreeSa              :", degreeSa
1851
        print "intervalSa            :", intervalSa.str(style='brackets')
1852
        print "currentApproxErrorSa  :", currentApproxErrorSa 
1853
        print "approxAccurSa         :", approxAccurSa 
1854
    radiusSa = intervalSa.absolute_diameter() / 2
1855
    if debug:
1856
        print "log2(radius):", RR(radiusSa).log2()
1857
    iterIndex = 0
1858
    ## Build the "shaved" polynomial.
1859
    while True: 
1860
        ### Start with a 0 value expression.
1861
        resPolySo = pobyso_constant_0_sa_so()
1862
        roundedPolyApproxAccurSa = approxAccurSa / 2
1863
        currentRadiusPowerSa = 1 
1864
        for degree in xrange(0,degreeSa + 1):
1865
            #### At round 0, use the agressive formula. At round 1, run the
1866
            #    proved formula.
1867
            if iterIndex == 0:
1868
                roundingPowerSa = \
1869
                    floor(((currentRadiusPowerSa/roundedPolyApproxAccurSa)*(degree+1)).log2())
1870
            else:
1871
                roundingPowerSa = \
1872
                    floor(((currentRadiusPowerSa/roundedPolyApproxAccurSa)*(degreeSa+1)).log2())
1873
            ## Under extreme conditions the above formulas can evaluate under 2,
1874
            #   which is the minimal precision of an MPFR number.
1875
            if roundingPowerSa < 2:
1876
                roundingPowerSa = 2
1877
            if debug:
1878
                print "roundedPolyApproxAccurSa", roundedPolyApproxAccurSa
1879
                print "currentRadiusPowerSa", currentRadiusPowerSa
1880
                print "Current rounding exponent:", roundingPowerSa
1881
            currentRadiusPowerSa *= radiusSa
1882
            index1So = pobyso_constant_from_int_sa_so(degree)
1883
            index2So = pobyso_constant_from_int_sa_so(degree)
1884
            ### Create a monomial with:
1885
            #   - the coefficient in the initial monomial at the current degrree;
1886
            #   - the current exponent;
1887
            #   - the free variable.
1888
            cmonSo  = \
1889
                sollya_lib_build_function_mul(sollya_lib_coeff(polySo, index1So),
1890
                                              sollya_lib_build_function_pow( \
1891
                                                sollya_lib_build_function_free_variable(), \
1892
                                                index2So))
1893
            roundingPowerSo = pobyso_constant_from_int_sa_so(roundingPowerSa)
1894
            cmonrSo = pobyso_round_coefficients_single_so_so(cmonSo, roundingPowerSo)
1895
            sollya_lib_clear_obj(cmonSo)
1896
            ### Add to the result polynomial.
1897
            resPolySo = sollya_lib_build_function_add(resPolySo,
1898
                                                      cmonrSo)
1899
        # End for.
1900
        ### Check the new polynomial.
1901
        freeVarSo     = sollya_lib_build_function_free_variable()
1902
        changeVarSo   = sollya_lib_sub(freeVarSo, icSo)
1903
        resPolyCvSo   = sollya_lib_evaluate(resPolySo, changeVarSo)
1904
        errFuncSo     = sollya_lib_build_function_sub(sollya_lib_copy_obj(funcSo), 
1905
                                                      resPolyCvSo)
1906
        infNormSo = sollya_lib_dirtyinfnorm(errFuncSo, intervalSo)
1907
        ### This also clears resPolyCvSo.
1908
        sollya_lib_clear_obj(errFuncSo)
1909
        cerrSa    = pobyso_get_constant_as_rn_so_sa(infNormSo)
1910
        if debug:
1911
            print "Error of the new polynomial:", cerrSa
1912
        ### If at round 1, return the initial polynomial error. This should
1913
        #   never happen since the rounding algorithm is proved. But some 
1914
        #   circumstances may break it (e.g. internal precision of tools).
1915
        if cerrSa > approxAccurSa:
1916
            if iterIndex > 0: # Round 1 and beyond.
1917
                sollya_lib_clear_obj(resPolySo)
1918
                sollya_lib_clear_obj(infNormSo)
1919
                #### Do not return the arguments but copies: the caller may free
1920
                #    free the former as inutile after call.
1921
                return (sollya_lib_copy_obj(polySo), 
1922
                        sollya_lib_copy_obj(currentApproxErrorSo))
1923
            else: # Round 0 (agressive rounding), got round 1 (proved rounding)
1924
                sollya_lib_clear_obj(resPolySo)
1925
                sollya_lib_clear_obj(infNormSo)
1926
                iterIndex += 1
1927
                continue
1928
        ### If get here it is because cerrSa <= approxAccurSa
1929
        ### Approximation error of the new polynomial is acceptable.
1930
        return (resPolySo, infNormSo)
1931
    # End while True
1932
# End pobyso_round_coefficients_progressive_so_so
1933
    
1934
def pobyso_round_coefficients_single_so_so(polySo, commonPrecSo):
1935
    """
1936
    Create a rounded coefficients polynomial from polynomial argument to
1937
    the number of bits in size argument.
1938
    All coefficients are set to the same precision.
1939
    """
1940
    ## TODO: check arguments.
1941
    endEllipListSo = pobyso_build_end_elliptic_list_so_so(commonPrecSo)
1942
    polySo = sollya_lib_roundcoefficients(polySo, endEllipListSo, None)
1943
    sollya_lib_clear_obj(endEllipListSo)
1944
    #sollya_lib_clear_obj(endEllipListSo)
1945
    return polySo
1946
    
1947
# End pobyso_round_coefficients_single_so_so
1948

    
1949
def pobyso_set_canonical_off():
1950
    sollya_lib_set_canonical(sollya_lib_off())
1951

    
1952
def pobyso_set_canonical_on():
1953
    sollya_lib_set_canonical(sollya_lib_on())
1954

    
1955
def pobyso_set_prec(p):
1956
    """ Legacy function. See pobyso_set_prec_sa_so. """
1957
    pobyso_set_prec_sa_so(p)
1958

    
1959
def pobyso_set_prec_sa_so(p):
1960
    #a = c_int(p)
1961
    #precSo = c_void_p(sollya_lib_constant_from_int(a))
1962
    #precSo = sollya_lib_constant_from_int(a)
1963
    precSo = pobyso_constant_from_int_sa_so(p)
1964
    sollya_lib_set_prec(precSo)
1965
    sollya_lib_clear_obj(precSo)
1966
# End pobyso_set_prec_sa_so.
1967

    
1968
def pobyso_set_prec_so_so(newPrecSo):
1969
    sollya_lib_set_prec(newPrecSo)
1970
# End pobyso_set_prec_so_so.
1971

    
1972
def pobyso_inf_so_so(intervalSo):
1973
    """
1974
    Very thin wrapper around sollya_lib_inf().
1975
    """
1976
    return sollya_lib_inf(intervalSo)
1977
# End pobyso_inf_so_so.
1978
#   
1979
def pobyso_supnorm_so_sa(polySo, funcSo, intervalSo, errorTypeSo = None,\
1980
                         accuracySo = None, realFieldSa = None):
1981
    """
1982
    Computes the supremum norm from Solly input arguments and returns a
1983
    Sage floating-point number whose precision is set by the only Sage argument.
1984
    
1985
    The returned value is the maximum of the absolute values of the range
1986
    elements  returned by the Sollya supnorm functions
1987
    """
1988
    supNormRangeSo = pobyso_supnorm_so_so(polySo, 
1989
                                          funcSo, 
1990
                                          intervalSo, 
1991
                                          errorTypeSo,
1992
                                          accuracySo)
1993
    supNormSo = pobyso_range_max_abs_so_so(supNormRangeSo)
1994
    sollya_lib_clear_obj(supNormRangeSo)
1995
    #pobyso_autoprint(supNormSo)
1996
    supNormSa = pobyso_get_constant_as_rn_with_rf_so_sa(supNormSo, realFieldSa)
1997
    sollya_lib_clear_obj(supNormSo)
1998
    return supNormSa 
1999
# End pobyso_supnorm_so_sa.
2000
#
2001
def pobyso_supnorm_so_so(polySo, funcSo, intervalSo, errorTypeSo = None,\
2002
                         accuracySo = None):
2003
    """
2004
    Computes the supnorm of the approximation error between the given 
2005
    polynomial and function. Attention: returns a range!
2006
    errorTypeSo defaults to "absolute".
2007
    accuracySo defaults to 2^(-40).
2008
    """
2009
    if errorTypeSo is None:
2010
        errorTypeSo = sollya_lib_absolute(None)
2011
        errorTypeIsNone = True
2012
    else:
2013
        errorTypeIsNone = False
2014
    #
2015
    if accuracySo is None:
2016
        # Notice the **: we are in Pythonland here!
2017
        accuracySo = pobyso_constant_sa_so(RR(2**(-40)))
2018
        accuracyIsNone = True
2019
    else:
2020
        accuracyIsNone = False
2021
    #pobyso_autoprint(accuracySo)
2022
    resultSo = \
2023
        sollya_lib_supnorm(polySo, funcSo, intervalSo, errorTypeSo, \
2024
                              accuracySo)
2025
    if errorTypeIsNone:
2026
        sollya_lib_clear_obj(errorTypeSo)
2027
    if accuracyIsNone:
2028
        sollya_lib_clear_obj(accuracySo)
2029
    return resultSo
2030
# End pobyso_supnorm_so_so
2031
#
2032
def pobyso_taylor_expansion_no_change_var_so_so(functionSo, 
2033
                                                degreeSo, 
2034
                                                rangeSo,
2035
                                                errorTypeSo=None, 
2036
                                                sollyaPrecSo=None):
2037
    """
2038
    Compute the Taylor expansion without the variable change
2039
    x -> x-intervalCenter.
2040
    If errorTypeSo is None, absolute is used.
2041
    If sollyaPrecSo is None, Sollya internal precision is not changed. 
2042
    """
2043
    # Change internal Sollya precision, if needed.
2044
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
2045
    sollyaPrecChanged = False
2046
    if sollyaPrecSo is None:
2047
        pass
2048
    else:
2049
        sollya_lib_set_prec(sollyaPrecSo)
2050
        sollyaPrecChanged = True
2051
    # Error type stuff: default to absolute.
2052
    if errorTypeSo is None:
2053
        errorTypeIsNone = True
2054
        errorTypeSo = sollya_lib_absolute(None)
2055
    else:
2056
        errorTypeIsNone = False
2057
    intervalCenterSo = sollya_lib_mid(rangeSo, None)
2058
    taylorFormSo = sollya_lib_taylorform(functionSo, degreeSo,
2059
                                         intervalCenterSo,
2060
                                         rangeSo, errorTypeSo, None)
2061
    # Object taylorFormListSaSo is a Python list of Sollya objects references 
2062
    #  that are copies of the elements of taylorFormSo.
2063
    # pobyso_get_list_elements_so_so clears taylorFormSo.
2064
    (taylorFormListSaSo, numElementsSa, isEndEllipticSa) = \
2065
        pobyso_get_list_elements_so_so(taylorFormSo)
2066
    ## Copy needed here since polySo will be returned and taylorFormListSaSo
2067
    #  will be cleared.
2068
    polySo = sollya_lib_copy_obj(taylorFormListSaSo[0])
2069
    #print "Num elements:", numElementsSa
2070
    sollya_lib_clear_obj(taylorFormSo)
2071
    # No copy_obj needed here: a new objects are created.
2072
    maxErrorSo    = sollya_lib_sup(taylorFormListSaSo[2])
2073
    minErrorSo    = sollya_lib_inf(taylorFormListSaSo[2])
2074
    # List taylorFormListSaSo is not needed anymore.
2075
    pobyso_clear_taylorform_sa_so(taylorFormListSaSo)
2076
    absMaxErrorSo = sollya_lib_abs(maxErrorSo)
2077
    absMinErrorSo = sollya_lib_abs(minErrorSo)
2078
    sollya_lib_clear_obj(maxErrorSo)
2079
    sollya_lib_clear_obj(minErrorSo)
2080
    absMaxErrorSa = pobyso_get_constant_as_rn_so_sa(absMaxErrorSo)
2081
    absMinErrorSa = pobyso_get_constant_as_rn_so_sa(absMinErrorSo)
2082
    #
2083
    if errorTypeIsNone:
2084
        sollya_lib_clear_obj(errorTypeSo)
2085
    ## If changed, reset the Sollya working precision.
2086
    if sollyaPrecChanged:
2087
        sollya_lib_set_prec(initialSollyaPrecSo)
2088
    sollya_lib_clear_obj(initialSollyaPrecSo)
2089
    ## According to what error is the largest, return the errors.
2090
    if absMaxErrorSa > absMinErrorSa:
2091
        sollya_lib_clear_obj(absMinErrorSo)
2092
        return (polySo, intervalCenterSo, absMaxErrorSo)
2093
    else:
2094
        sollya_lib_clear_obj(absMaxErrorSo)
2095
        return (polySo, intervalCenterSo, absMinErrorSo)
2096
# end pobyso_taylor_expansion_no_change_var_so_so
2097

    
2098
def pobyso_taylor_expansion_with_change_var_so_so(functionSo, degreeSo, \
2099
                                                  rangeSo, \
2100
                                                  errorTypeSo=None, \
2101
                                                  sollyaPrecSo=None):
2102
    """
2103
    Compute the Taylor expansion with the variable change
2104
    x -> (x-intervalCenter) included.
2105
    """
2106
    # Change Sollya internal precision, if need.
2107
    sollyaPrecChanged = False
2108
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
2109
    if sollyaPrecSo is None:
2110
        pass
2111
    else:
2112
        sollya_lib_set_prec(sollyaPrecSo)
2113
        sollyaPrecChanged = True
2114
    #
2115
    # Error type stuff: default to absolute.
2116
    if errorTypeSo is None:
2117
        errorTypeIsNone = True
2118
        errorTypeSo = sollya_lib_absolute(None)
2119
    else:
2120
        errorTypeIsNone = False
2121
    intervalCenterSo = sollya_lib_mid(rangeSo)
2122
    taylorFormSo = sollya_lib_taylorform(functionSo, degreeSo, \
2123
                                         intervalCenterSo, \
2124
                                         rangeSo, errorTypeSo, None)
2125
    # Object taylorFormListSaSo is a Python list of Sollya objects references 
2126
    # that are copies of the elements of taylorFormSo.
2127
    # pobyso_get_list_elements_so_so clears taylorFormSo.
2128
    (taylorFormListSaSo, numElements, isEndElliptic) = \
2129
        pobyso_get_list_elements_so_so(taylorFormSo)
2130
    sollya_lib_clear_obj(taylorFormSo)
2131
    polySo = taylorFormListSaSo[0]
2132
    ## Maximum error computation with taylorFormListSaSo[2], a range
2133
    #  holding the actual error. Bounds can be negative.
2134
    maxErrorSo    = sollya_lib_sup(taylorFormListSaSo[2])
2135
    minErrorSo    = sollya_lib_inf(taylorFormListSaSo[2])
2136
    absMaxErrorSo = sollya_lib_abs(maxErrorSo)
2137
    absMinErrorSo = sollya_lib_abs(minErrorSo)
2138
    sollya_lib_clear_obj(maxErrorSo)
2139
    sollya_lib_clear_obj(minErrorSo)
2140
    absMaxErrorSa = pobyso_get_constant_as_rn_so_sa(absMaxErrorSo)
2141
    absMinErrorSa = pobyso_get_constant_as_rn_so_sa(absMinErrorSo)
2142
    changeVarExpSo = sollya_lib_build_function_sub(\
2143
                       sollya_lib_build_function_free_variable(),\
2144
                       sollya_lib_copy_obj(intervalCenterSo))
2145
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpSo)
2146
    # List taylorFormListSaSo is not needed anymore.
2147
    pobyso_clear_taylorform_sa_so(taylorFormListSaSo)
2148
    sollya_lib_clear_obj(changeVarExpSo)
2149
    # If changed, reset the Sollya working precision.
2150
    if sollyaPrecChanged:
2151
        sollya_lib_set_prec(initialSollyaPrecSo)
2152
    sollya_lib_clear_obj(initialSollyaPrecSo)
2153
    if errorTypeIsNone:
2154
        sollya_lib_clear_obj(errorTypeSo)
2155
    # Do not clear maxErrorSo.
2156
    if absMaxErrorSa > absMinErrorSa:
2157
        sollya_lib_clear_obj(absMinErrorSo)
2158
        return((polyVarChangedSo, intervalCenterSo, absMaxErrorSo))
2159
    else:
2160
        sollya_lib_clear_obj(absMaxErrorSo)
2161
        return((polyVarChangedSo, intervalCenterSo, absMinErrorSo))
2162
# end pobyso_taylor_expansion_with_change_var_so_so
2163

    
2164
def pobyso_taylor(function, degree, point):
2165
    """ Legacy function. See pobysoTaylor_so_so. """
2166
    return(pobyso_taylor_so_so(function, degree, point))
2167

    
2168
def pobyso_taylor_so_so(functionSo, degreeSo, pointSo):
2169
    return(sollya_lib_taylor(functionSo, degreeSo, pointSo))
2170
    
2171
def pobyso_taylorform(function, degree, point = None, 
2172
                      interval = None, errorType=None):
2173
    """ Legacy function. See pobyso_taylorform_sa_sa;"""
2174
    
2175
def pobyso_taylorform_sa_sa(functionSa, \
2176
                            degreeSa, \
2177
                            pointSa, \
2178
                            intervalSa=None, \
2179
                            errorTypeSa=None, \
2180
                            precisionSa=None):
2181
    """
2182
    Compute the Taylor form of 'degreeSa' for 'functionSa' at 'pointSa' 
2183
    for 'intervalSa' with 'errorTypeSa' (a string) using 'precisionSa'. 
2184
    point: must be a Real or a Real interval.
2185
    return the Taylor form as an array
2186
    TODO: take care of the interval and of the point when it is an interval;
2187
          when errorType is not None;
2188
          take care of the other elements of the Taylor form (coefficients 
2189
          errors and delta.
2190
    """
2191
    # Absolute as the default error.
2192
    if errorTypeSa is None:
2193
        errorTypeSo = sollya_lib_absolute()
2194
    elif errorTypeSa == "relative":
2195
        errorTypeSo = sollya_lib_relative()
2196
    elif errortypeSa == "absolute":
2197
        errorTypeSo = sollya_lib_absolute()
2198
    else:
2199
        # No clean up needed.
2200
        return None
2201
    # Global precision stuff
2202
    sollyaPrecisionChangedSa = False
2203
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
2204
    if precisionSa is None:
2205
        precSa = initialSollyaPrecSa
2206
    else:
2207
        if precSa > initialSollyaPrecSa:
2208
            if precSa <= 2:
2209
                print inspect.stack()[0][3], ":precision change <= 2 requested."
2210
            pobyso_set_prec_sa_so(precSa)
2211
            sollyaPrecisionChangedSa = True
2212
    #        
2213
    if len(functionSa.variables()) > 0:
2214
        varSa = functionSa.variables()[0]
2215
        pobyso_name_free_variable_sa_so(str(varSa))
2216
    # In any case (point or interval) the parent of pointSa has a precision
2217
    # method.
2218
    pointPrecSa = pointSa.parent().precision()
2219
    if precSa > pointPrecSa:
2220
        pointPrecSa = precSa
2221
    # In any case (point or interval) pointSa has a base_ring() method.
2222
    pointBaseRingString = str(pointSa.base_ring())
2223
    if re.search('Interval', pointBaseRingString) is None: # Point
2224
        pointSo = pobyso_constant_sa_so(pointSa, pointPrecSa)
2225
    else: # Interval.
2226
        pointSo = pobyso_interval_to_range_sa_so(pointSa, pointPrecSa)
2227
    # Sollyafy the function.
2228
    functionSo = pobyso_parse_string_sa_so(functionSa._assume_str().replace('_SAGE_VAR_', ''))
2229
    if sollya_lib_obj_is_error(functionSo):
2230
        print "pobyso_tailorform: function string can't be parsed!"
2231
        return None
2232
    # Sollyafy the degree
2233
    degreeSo = sollya_lib_constant_from_int(int(degreeSa))
2234
    # Sollyafy the point
2235
    # Call Sollya
2236
    taylorFormSo = \
2237
        sollya_lib_taylorform(functionSo, degreeSo, pointSo, errorTypeSo,\
2238
                                         None)
2239
    sollya_lib_clear_obj(functionSo)
2240
    sollya_lib_clear_obj(degreeSo)
2241
    sollya_lib_clear_obj(pointSo)
2242
    sollya_lib_clear_obj(errorTypeSo)
2243
    (tfsAsList, numElements, isEndElliptic) = \
2244
            pobyso_get_list_elements_so_so(taylorFormSo)
2245
    polySo = tfsAsList[0]
2246
    maxPrecision = pobyso_get_max_prec_of_exp_so_sa(polySo)
2247
    polyRealField = RealField(maxPrecision)
2248
    expSa = pobyso_get_sage_exp_from_sollya_exp_so_sa(polySo, polyRealField)
2249
    if sollyaPrecisionChangedSa:
2250
        sollya_lib_set_prec(initialSollyaPrecSo)
2251
    sollya_lib_clear_obj(initialSollyaPrecSo)
2252
    polynomialRing = polyRealField[str(varSa)]
2253
    polySa = polynomial(expSa, polynomialRing)
2254
    taylorFormSa = [polySa]
2255
    # Final clean-up.
2256
    sollya_lib_clear_obj(taylorFormSo)
2257
    return(taylorFormSa)
2258
# End pobyso_taylor_form_sa_sa
2259

    
2260
def pobyso_taylorform_so_so(functionSo, degreeSo, pointSo, intervalSo=None, \
2261
                            errorTypeSo=None):
2262
    createdErrorType = False
2263
    if errorTypeSo is None:
2264
        errorTypeSo = sollya_lib_absolute()
2265
        createdErrorType = True
2266
    else:
2267
        #TODO: deal with the other case.
2268
        pass
2269
    if intervalSo is None:
2270
        resultSo = sollya_lib_taylorform(functionSo, degreeSo, pointSo, \
2271
                                         errorTypeSo, None)
2272
    else:
2273
        resultSo = sollya_lib_taylorform(functionSo, degreeSo, pointSo, \
2274
                                         intervalSo, errorTypeSo, None)
2275
    if createdErrorType:
2276
        sollya_lib_clear_obj(errorTypeSo)
2277
    return resultSo
2278
        
2279

    
2280
def pobyso_univar_polynomial_print_reverse(polySa):
2281
    """ Legacy function. See pobyso_univar_polynomial_print_reverse_sa_sa. """
2282
    return(pobyso_univar_polynomial_print_reverse_sa_sa(polySa))
2283

    
2284
def pobyso_univar_polynomial_print_reverse_sa_sa(polySa):
2285
    """
2286
    Return the string representation of a univariate polynomial with
2287
    monomials ordered in the x^0..x^n order of the monomials.
2288
    Remember: Sage
2289
    """
2290
    polynomialRing = polySa.base_ring()
2291
    # A very expensive solution:
2292
    # -create a fake multivariate polynomial field with only one variable,
2293
    #   specifying a negative lexicographical order;
2294
    mpolynomialRing = PolynomialRing(polynomialRing.base(), \
2295
                                     polynomialRing.variable_name(), \
2296
                                     1, order='neglex')
2297
    # - convert the univariate argument polynomial into a multivariate
2298
    #   version;
2299
    p = mpolynomialRing(polySa)
2300
    # - return the string representation of the converted form.
2301
    # There is no simple str() method defined for p's class.
2302
    return(p.__str__())
2303
#
2304
#print pobyso_get_prec()  
2305
pobyso_set_prec(165)
2306
#print pobyso_get_prec()  
2307
#a=100
2308
#print type(a)
2309
#id(a)
2310
#print "Max arity: ", pobyso_max_arity
2311
#print "Function tripleDouble (43) as a string: ", pobyso_function_type_as_string(43)
2312
#print "Function None (44) as a string: ", pobyso_function_type_as_string(44)
2313
sys.stderr.write("\t...Pobyso check done.\n")