Statistiques
| Révision :

root / pobysoPythonSage / src / sageSLZ / sageSLZ.sage @ 119

Historique | Voir | Annoter | Télécharger (28,96 ko)

1
r"""
2
Sage core functions needed for the implementation of SLZ.
3

    
4
AUTHORS:
5
- S.T. (2013-08): initial version
6

    
7
Examples:
8

    
9
TODO::
10
"""
11
print "sageSLZ loading..."
12
#
13
def slz_check_htr_value(function, htrValue, lowerBound, upperBound, precision, \
14
                        degree, targetHardnessToRound, alpha):
15
    """
16
    Check an Hard-to-round value.
17
    """
18
    polyApproxPrec = targetHardnessToRound + 1
19
    polyTargetHardnessToRound = targetHardnessToRound + 1
20
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
21
    RRR = htrValue.parent()
22
    #
23
    ## Compute the scaled function.
24
    fff = slz_compute_scaled_function(f, lowerBound, upperBound, precision)[0]
25
    print "Scaled function:", fff
26
    #
27
    ## Compute the scaling.
28
    boundsIntervalRifSa = RealIntervalField(precision)
29
    domainBoundsInterval = boundsIntervalRifSa(lowerBound, upperBound)
30
    scalingExpressions = \
31
        slz_interval_scaling_expression(domainBoundsInterval, i)
32
    #
33
    ## Get the polynomials, bounds, etc. for all the interval.
34
    resultListOfTuplesOfSo = \
35
        slz_get_intervals_and_polynomials(f, degree, lowerBound, upperBound, \
36
                                          precision, internalSollyaPrec,\
37
                                          2^-(polyApproxPrec))
38
    #
39
    ## We only want one interval.
40
    if len(resultListOfTuplesOfSo) > 1:
41
        print "Too many intervals! Aborting!"
42
        exit
43
    #
44
    ## Get the first tuple of Sollya objects as Sage objects. 
45
    firstTupleSa = \
46
        slz_interval_and_polynomial_to_sage(resultListOfTuplesOfSo[0])
47
    pobyso_set_canonical_on()
48
    #
49
    print "Floatting point polynomial:", firstTupleSa[0]
50
    print "with coefficients precision:", firstTupleSa[0].base_ring().prec()
51
    #
52
    ## From a polynomial over a real ring, create a polynomial over the 
53
    #  rationals ring.
54
    rationalPolynomial = \
55
        slz_float_poly_of_float_to_rat_poly_of_rat(firstTupleSa[0])
56
    print "Rational polynomial:", rationalPolynomial
57
    #
58
    ## Create a polynomial over the rationals that will take integer 
59
    # variables instead of rational. 
60
    rationalPolynomialOfIntegers = \
61
        slz_rat_poly_of_rat_to_rat_poly_of_int(rationalPolynomial, precision)
62
    print "Type:", type(rationalPolynomialOfIntegers)
63
    print "Rational polynomial of integers:", rationalPolynomialOfIntegers
64
    #
65
    ## Check the rational polynomial of integers variables.
66
    # (check against the scaled function).
67
    toIntegerFactor = 2^(precision-1)
68
    intervalCenterAsIntegerSa = int(firstTupleSa[3] * toIntegerFactor)
69
    print "Interval center as integer:", intervalCenterAsIntegerSa
70
    lowerBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[0] * \
71
                                toIntegerFactor) - intervalCenterAsIntegerSa
72
    upperBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[1] * \
73
                                toIntegerFactor) - intervalCenterAsIntegerSa
74
    print "Lower bound as integer:", lowerBoundAsIntegerSa
75
    print "Upper bound as integer:", upperBoundAsIntegerSa
76
    print "Image of the lower bound by the scaled function", \
77
            fff(firstTupleSa[2].endpoints()[0])
78
    print "Image of the lower bound by the approximation polynomial of ints:", \
79
            RRR(rationalPolynomialOfIntegers(lowerBoundAsIntegerSa))
80
    print "Image of the center by the scaled function", fff(firstTupleSa[3])
81
    print "Image of the center by the approximation polynomial of ints:", \
82
            RRR(rationalPolynomialOfIntegers(0))
83
    print "Image of the upper bound by the scaled function", \
84
            fff(firstTupleSa[2].endpoints()[1])
85
    print "Image of the upper bound by the approximation polynomial of ints:", \
86
            RRR(rationalPolynomialOfIntegers(upperBoundAsIntegerSa))
87

    
88
# End slz_check_htr_value.
89
#
90
def slz_compute_binade_bounds(number, emin):
91
    """
92
    For given "real number", compute the bounds of the binade it belongs to.
93
    TODO::
94
        Deal with the emax exponent.
95
    """
96
    RF = number.parent()
97
    precision = RF.precision()
98
    RRF = RealField(2 * precision)
99
    if number == 0:
100
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
101
    l2 = RRF(number).abs().log2()
102
    offset = int(l2)
103
    if l2 >= 0:
104
        if number >= 0:
105
            lb = RF(2^offset)
106
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
107
        else: #number < 0
108
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
109
            ub = -RF(2^offset)
110
    else: # log2 < 0
111
        if l2 < emin: # Denormal
112
            print "Denormal:", l2
113
            if number >= 0:
114
                lb = RF(0)
115
                ub = RF(2^(emin)) - RF(2^(emin-precision))
116
            else: # number <= 0
117
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
118
                ub = RF(0)
119
        elif l2 > emin: # Normal number other than +/-2^emin.
120
            if number >= 0:
121
                lb = RF(2^(offset-1))
122
                ub = RF(2^(offset)) - RF(2^(-precision+offset))
123
            else: # number < 0
124
                lb = -RF(2^(offset) - 2^(-precision+offset))
125
                ub = -RF(2^(offset-1))
126
        else: # +/-2^emin
127
            if number >= 0:
128
                lb = RF(2^(offset))
129
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
130
            else: # number < 0
131
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
132
                ub = -RF(2^(offset))
133
    return (lb, ub)
134
# End slz_compute_binade_bounds
135
#
136
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa, 
137
                                        upperBoundSa, approxPrecSa, 
138
                                        sollyaPrecSa=None):
139
    """
140
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
141
    a polynomial that approximates the function on a an interval starting
142
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
143
    approximates with the expected precision.
144
    The interval upper bound is lowered until the expected approximation 
145
    precision is reached.
146
    The polynomial, the bounds, the center of the interval and the error
147
    are returned.
148
    """
149
    RRR = lowerBoundSa.parent()
150
    intervalShrinkConstFactorSa = RRR('0.5')
151
    absoluteErrorTypeSo = pobyso_absolute_so_so()
152
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
153
    currentUpperBoundSa = upperBoundSa
154
    currentLowerBoundSa = lowerBoundSa
155
    # What we want here is the polynomial without the variable change, 
156
    # since our actual variable will be x-intervalCenter defined over the 
157
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
158
    (polySo, intervalCenterSo, maxErrorSo) = \
159
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
160
                                                    currentRangeSo, 
161
                                                    absoluteErrorTypeSo)
162
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
163
    while maxErrorSa > approxPrecSa:
164
        #print "++Approximation error:", maxErrorSa
165
        sollya_lib_clear_obj(maxErrorSo)
166
        sollya_lib_clear_obj(polySo)
167
        sollya_lib_clear_obj(intervalCenterSo)
168
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
169
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
170
        #errorRatioSa = approxPrecSa/maxErrorSa
171
        #print "Error ratio: ", errorRatioSa
172
        if shrinkFactorSa > intervalShrinkConstFactorSa:
173
            actualShrinkFactorSa = intervalShrinkConstFactorSa
174
            #print "Fixed"
175
        else:
176
            actualShrinkFactorSa = shrinkFactorSa
177
            #print "Computed",shrinkFactorSa,maxErrorSa
178
            #print shrinkFactorSa, maxErrorSa
179
        #print "Shrink factor", actualShrinkFactorSa
180
        currentUpperBoundSa = currentLowerBoundSa + \
181
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
182
                                   actualShrinkFactorSa
183
        #print "Current upper bound:", currentUpperBoundSa
184
        sollya_lib_clear_obj(currentRangeSo)
185
        sollya_lib_clear_obj(polySo)
186
        if currentUpperBoundSa <= currentLowerBoundSa or \
187
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
188
            sollya_lib_clear_obj(absoluteErrorTypeSo)
189
            print "Can't find an interval."
190
            print "Use either or both a higher polynomial degree or a higher",
191
            print "internal precision."
192
            print "Aborting!"
193
            return (None, None, None, None)
194
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
195
                                                      currentUpperBoundSa)
196
        # print "New interval:",
197
        # pobyso_autoprint(currentRangeSo)
198
        (polySo, intervalCenterSo, maxErrorSo) = \
199
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
200
                                                        currentRangeSo, 
201
                                                        absoluteErrorTypeSo)
202
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
203
        #print "Max errorSo:",
204
        #pobyso_autoprint(maxErrorSo)
205
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
206
        #print "Max errorSa:", maxErrorSa
207
        #print "Sollya prec:",
208
        #pobyso_autoprint(sollya_lib_get_prec(None))
209
    sollya_lib_clear_obj(absoluteErrorTypeSo)
210
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
211
# End slz_compute_polynomial_and_interval
212

    
213
def slz_compute_reduced_polynomials(reducedMatrix,
214
                                    knownMonomials,
215
                                    var1,
216
                                    var1Bound,
217
                                    var2,
218
                                    var2Bound):
219
    """
220
    From a reduced matrix, holding the coefficients, from a monomials list,
221
    from the bounds of each variable, compute the corresponding polynomials
222
    scaled back by dividing by the "right" powers of the variables bounds.
223
    
224
    The elements in knownMonomials must be of the "right" polynomial type.
225
    They set the polynomial type of the output polynomials list.
226
    """
227
    
228
    # TODO: check input arguments.
229
    reducedPolynomials = []
230
    #print "type var1:", type(var1), " - type var2:", type(var2)
231
    for matrixRow in reducedMatrix.rows():
232
        currentPolynomial = 0
233
        for colIndex in xrange(0, len(knownMonomials)):
234
            currentCoefficient = matrixRow[colIndex]
235
            if currentCoefficient != 0:
236
                #print "Current coefficient:", currentCoefficient
237
                currentMonomial = knownMonomials[colIndex]
238
                parentRing = currentMonomial.parent()
239
                #print "Monomial as multivariate polynomial:", \
240
                #currentMonomial, type(currentMonomial)
241
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
242
                #print "Degree in var", var1, ":", degreeInVar1
243
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
244
                #print "Degree in var", var2, ":", degreeInVar2
245
                if degreeInVar1 > 0:
246
                    currentCoefficient = \
247
                        currentCoefficient / var1Bound^degreeInVar1
248
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
249
                    #print "Current coefficient(1)", currentCoefficient
250
                if degreeInVar2 > 0:
251
                    currentCoefficient = \
252
                        currentCoefficient / var2Bound^degreeInVar2
253
                    #print "Current coefficient(2)", currentCoefficient
254
                #print "Current reduced monomial:", (currentCoefficient * \
255
                #                                    currentMonomial)
256
                currentPolynomial += (currentCoefficient * currentMonomial)
257
                #print "Current polynomial:", currentPolynomial
258
            # End if
259
        # End for colIndex.
260
        #print "Type of the current polynomial:", type(currentPolynomial)
261
        reducedPolynomials.append(currentPolynomial)
262
    return reducedPolynomials 
263
# End slz_compute_reduced_polynomials.
264

    
265
def slz_compute_scaled_function(functionSa,
266
                                lowerBoundSa,
267
                                upperBoundSa,
268
                                floatingPointPrecSa):
269
    """
270
    From a function, compute the scaled function whose domain
271
    is included in [1, 2) and whose image is also included in [1,2).
272
    Return a tuple: 
273
    [0]: the scaled function
274
    [1]: the scaled domain lower bound
275
    [2]: the scaled domain upper bound
276
    [3]: the scaled image lower bound
277
    [4]: the scaled image upper bound
278
    """
279
    x = functionSa.variables()[0]
280
    # Reassert f as a function (an not a mere expression).
281
    
282
    # Scalling the domain -> [1,2[.
283
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
284
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
285
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
286
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
287
    print "domainScalingExpression for argument :", domainScalingExpressionSa
288
    print "f: ", f
289
    ff = f.subs({x : domainScalingExpressionSa})
290
    #ff = f.subs_expr(x==domainScalingExpressionSa)
291
    domainScalingFunction(x) = invDomainScalingExpressionSa
292
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
293
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
294
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
295
    #
296
    # Scalling the image -> [1,2[.
297
    flbSa = f(lowerBoundSa).n()
298
    fubSa = f(upperBoundSa).n()
299
    if flbSa <= fubSa: # Increasing
300
        imageBinadeBottomSa = floor(flbSa.log2())
301
    else: # Decreasing
302
        imageBinadeBottomSa = floor(fubSa.log2())
303
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
304
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
305
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
306
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
307
    iis = invImageScalingExpressionSa.function(x)
308
    fff = iis.subs({x:ff})
309
    print "fff:", fff,
310
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
311
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
312
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
313

    
314
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
315
    # Create a polynomial over the rationals.
316
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
317
    return(polynomialRing(polyOfFloat))
318
# End slz_float_poly_of_float_to_rat_poly_of_rat.
319

    
320
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
321
                                      lowerBoundSa, 
322
                                      upperBoundSa, floatingPointPrecSa, 
323
                                      internalSollyaPrecSa, approxPrecSa):
324
    """
325
    Under the assumption that:
326
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
327
    - lowerBound and upperBound belong to the same binade.
328
    from a:
329
    - function;
330
    - a degree
331
    - a pair of bounds;
332
    - the floating-point precision we work on;
333
    - the internal Sollya precision;
334
    - the requested approximation error
335
    The initial interval is, possibly, splitted into smaller intervals.
336
    It return a list of tuples, each made of:
337
    - a first polynomial (without the changed variable f(x) = p(x-x0));
338
    - a second polynomial (with a changed variable f(x) = q(x))
339
    - the approximation interval;
340
    - the center, x0, of the interval;
341
    - the corresponding approximation error.
342
    TODO: fix endless looping for some parameters sets.
343
    """
344
    # Set Sollya to the necessary internal precision.
345
    currentSollyaPrecSo = pobyso_get_prec_so()
346
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
347
    if internalSollyaPrecSa > currentSollyaPrecSa:
348
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
349
    #
350
    x = functionSa.variables()[0] # Actual variable name can be anything.
351
    # Scaled function: [1=,2] -> [1,2].
352
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
353
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
354
                slz_compute_scaled_function(functionSa,                       \
355
                                            lowerBoundSa,                     \
356
                                            upperBoundSa,                     \
357
                                            floatingPointPrecSa)
358
    #
359
    resultArray = []
360
    #
361
    print "Approximation precision: ", RR(approxPrecSa)
362
    # Prepare the arguments for the Taylor expansion computation with Sollya.
363
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
364
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
365
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
366
                                                  scaledUpperBoundSa)
367
    # Compute the first Taylor expansion.
368
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
369
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
370
                                        scaledLowerBoundSa, scaledUpperBoundSa,
371
                                        approxPrecSa, internalSollyaPrecSa)
372
    if polySo is None:
373
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
374
        if internalSollyaPrecSa != currentSollyaPrecSa:
375
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
376
            sollya_lib_clear_obj(currentSollyaPrecSo)
377
        sollya_lib_clear_obj(functionSo)
378
        sollya_lib_clear_obj(degreeSo)
379
        sollya_lib_clear_obj(scaledBoundsSo)
380
        return None
381
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
382
                                              upperBoundSa.parent().precision()))
383
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
384
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
385
    #print "First approximation error:", errorSa
386
    # If the error and interval are OK a the first try, just return.
387
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
388
        # Change variable stuff in Sollya x -> x0-x.
389
        changeVarExpressionSo = sollya_lib_build_function_sub( \
390
                              sollya_lib_build_function_free_variable(), \
391
                              sollya_lib_copy_obj(intervalCenterSo))
392
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
393
        sollya_lib_clear_obj(changeVarExpressionSo)
394
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
395
                            intervalCenterSo, maxErrorSo))
396
        if internalSollyaPrecSa != currentSollyaPrecSa:
397
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
398
        sollya_lib_clear_obj(currentSollyaPrecSo)
399
        sollya_lib_clear_obj(functionSo)
400
        sollya_lib_clear_obj(degreeSo)
401
        sollya_lib_clear_obj(scaledBoundsSo)
402
        #print "Approximation error:", errorSa
403
        return resultArray
404
    # Compute the next upper bound.
405
    # The following ratio is always >= 1
406
    currentErrorRatio = approxPrecSa / errorSa
407
    # Starting point for the next upper bound.
408
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
409
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
410
    # Compute the increment. 
411
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
412
        currentScaledUpperBoundSa += \
413
                        currentErrorRatio * boundsWidthSa * 2
414
    else:  # [1, 1.5]
415
        currentScaledUpperBoundSa += \
416
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
417
    # Take into account the original interval upper bound.                     
418
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
419
        currentScaledUpperBoundSa = scaledUpperBoundSa
420
    # Compute the other expansions.
421
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
422
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
423
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
424
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
425
                                            currentScaledLowerBoundSa, 
426
                                            currentScaledUpperBoundSa, 
427
                                            approxPrecSa, 
428
                                            internalSollyaPrecSa)
429
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
430
        if  errorSa < approxPrecSa:
431
            # Change variable stuff
432
            #print "Approximation error:", errorSa
433
            changeVarExpressionSo = sollya_lib_build_function_sub(
434
                                    sollya_lib_build_function_free_variable(), 
435
                                    sollya_lib_copy_obj(intervalCenterSo))
436
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
437
            sollya_lib_clear_obj(changeVarExpressionSo)
438
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
439
                                intervalCenterSo, maxErrorSo))
440
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
441
        # Compute the next upper bound.
442
        # The following ratio is always >= 1
443
        currentErrorRatio = approxPrecSa / errorSa
444
        # Starting point for the next upper bound.
445
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
446
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
447
        # Compute the increment. 
448
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
449
            currentScaledUpperBoundSa += \
450
                            currentErrorRatio * boundsWidthSa * 2
451
        else:  # [1, 1.5]
452
            currentScaledUpperBoundSa += \
453
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
454
        #print "currentErrorRatio:", currentErrorRatio
455
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
456
        # Test for insufficient precision.
457
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
458
            print "Can't shrink the interval anymore!"
459
            print "You should consider increasing the Sollya internal precision"
460
            print "or the polynomial degree."
461
            print "Giving up!"
462
            if internalSollyaPrecSa != currentSollyaPrecSa:
463
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
464
            sollya_lib_clear_obj(currentSollyaPrecSo)
465
            sollya_lib_clear_obj(functionSo)
466
            sollya_lib_clear_obj(degreeSo)
467
            sollya_lib_clear_obj(scaledBoundsSo)
468
            return None
469
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
470
            currentScaledUpperBoundSa = scaledUpperBoundSa
471
    if internalSollyaPrecSa > currentSollyaPrecSa:
472
        pobyso_set_prec_so_so(currentSollyaPrecSo)
473
    sollya_lib_clear_obj(currentSollyaPrecSo)
474
    sollya_lib_clear_obj(functionSo)
475
    sollya_lib_clear_obj(degreeSo)
476
    sollya_lib_clear_obj(scaledBoundsSo)
477
    return(resultArray)
478
# End slz_get_intervals_and_polynomials
479

    
480

    
481
def slz_interval_scaling_expression(boundsInterval, expVar):
482
    """
483
    Compute the scaling expression to map an interval that span at most
484
    a single binade to [1, 2) and the inverse expression as well.
485
    Not very sure that the transformation makes sense for negative numbers.
486
    """
487
    # The scaling offset is only used for negative numbers.
488
    if abs(boundsInterval.endpoints()[0]) < 1:
489
        if boundsInterval.endpoints()[0] >= 0:
490
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
491
            invScalingCoeff = 1/scalingCoeff
492
            return((scalingCoeff * expVar, 
493
                    invScalingCoeff * expVar))
494
        else:
495
            scalingCoeff = \
496
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
497
            scalingOffset = -3 * scalingCoeff
498
            return((scalingCoeff * expVar + scalingOffset,
499
                    1/scalingCoeff * expVar + 3))
500
    else: 
501
        if boundsInterval.endpoints()[0] >= 0:
502
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
503
            scalingOffset = 0
504
            return((scalingCoeff * expVar, 
505
                    1/scalingCoeff * expVar))
506
        else:
507
            scalingCoeff = \
508
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
509
            scalingOffset =  -3 * scalingCoeff
510
            #scalingOffset = 0
511
            return((scalingCoeff * expVar + scalingOffset,
512
                    1/scalingCoeff * expVar + 3))
513

    
514
   
515
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
516
    """
517
    Compute the Sage version of the Taylor polynomial and it's
518
    companion data (interval, center...)
519
    The input parameter is a five elements tuple:
520
    - [0]: the polyomial (without variable change), as polynomial over a
521
           real ring;
522
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
523
           over a real ring;
524
    - [2]: the interval (as Sollya range);
525
    - [3]: the interval center;
526
    - [4]: the approximation error. 
527
    
528
    The function return a 5 elements tuple: formed with all the 
529
    input elements converted into their Sollya counterpart.
530
    """
531
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
532
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
533
    intervalSa = \
534
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
535
    centerSa = \
536
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
537
    errorSa = \
538
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
539
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
540
    # End slz_interval_and_polynomial_to_sage
541

    
542
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
543
                                                precision,
544
                                                targetHardnessToRound,
545
                                                variable1,
546
                                                variable2):
547
    """
548
    Creates a new multivariate polynomial with integer coefficients for use
549
     with the Coppersmith method.
550
    A the same time it computes :
551
    - 2^K (N);
552
    - 2^k (bound on the second variable)
553
    - lcm
554

    
555
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
556
                         variables.
557
    :param precision: the precision of the floating-point coefficients.
558
    :param targetHardnessToRound: the hardness to round we want to check.
559
    :param variable1: the first variable of the polynomial (an expression).
560
    :param variable2: the second variable of the polynomial (an expression).
561
    
562
    :returns: a 4 elements tuple:
563
                - the polynomial;
564
                - the modulus (N);
565
                - the t bound;
566
                - the lcm used to compute the integral coefficients and the 
567
                  module.
568
    """
569
    # Create a new integer polynomial ring.
570
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
571
    # Coefficients are issued in the increasing power order.
572
    ratPolyCoefficients = ratPolyOfInt.coefficients()
573
    # Print the reversed list for debugging.
574
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
575
    # Build the list of number we compute the lcm of.
576
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
577
    coefficientDenominators.append(2^precision)
578
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
579
    leastCommonMultiple = lcm(coefficientDenominators)
580
    # Compute the expression corresponding to the new polynomial
581
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
582
    #print coefficientNumerators
583
    polynomialExpression = 0
584
    power = 0
585
    # Iterate over two lists at the same time, stop when the shorter is
586
    # exhausted.
587
    for numerator, denominator in \
588
                        zip(coefficientNumerators, coefficientDenominators):
589
        multiplicator = leastCommonMultiple / denominator 
590
        newCoefficient = numerator * multiplicator
591
        polynomialExpression += newCoefficient * variable1^power
592
        power +=1
593
    polynomialExpression += - variable2
594
    return (IP(polynomialExpression),
595
            leastCommonMultiple / 2^precision, # 2^K or N.
596
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
597
            leastCommonMultiple) # If we want to make test computations.
598
        
599
# End slz_ratPoly_of_int_to_poly_for_coppersmith
600

    
601
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
602
                                          precision):
603
    """
604
    Makes a variable substitution into the input polynomial so that the output
605
    polynomial can take integer arguments.
606
    All variables of the input polynomial "have precision p". That is to say
607
    that they are rationals with denominator == 2^(precision - 1): 
608
    x = y/2^(precision - 1).
609
    We "incorporate" these denominators into the coefficients with, 
610
    respectively, the "right" power.
611
    """
612
    polynomialField = ratPolyOfRat.parent()
613
    polynomialVariable = ratPolyOfRat.variables()[0]
614
    #print "The polynomial field is:", polynomialField
615
    return \
616
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
617
                                   polynomialVariable/2^(precision-1)}))
618
    
619
    # Return a tuple:
620
    # - the bivariate integer polynomial in (i,j);
621
    # - 2^K
622
# End slz_rat_poly_of_rat_to_rat_poly_of_int
623

    
624

    
625
print "\t...sageSLZ loaded"