Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (29,08 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(polySo)
166
        sollya_lib_clear_obj(intervalCenterSo)
167
        sollya_lib_clear_obj(maxErrorSo)
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
        if currentUpperBoundSa <= currentLowerBoundSa or \
186
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
187
            sollya_lib_clear_obj(absoluteErrorTypeSo)
188
            print "Can't find an interval."
189
            print "Use either or both a higher polynomial degree or a higher",
190
            print "internal precision."
191
            print "Aborting!"
192
            return (None, None, None, None)
193
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
194
                                                      currentUpperBoundSa)
195
        # print "New interval:",
196
        # pobyso_autoprint(currentRangeSo)
197
        #print "Second Taylor expansion call."
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
    resultArray = []
345
    # Set Sollya to the necessary internal precision.
346
    precChangedSa = False
347
    currentSollyaPrecSo = pobyso_get_prec_so()
348
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
349
    if internalSollyaPrecSa > currentSollyaPrecSa:
350
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
351
        precChangedSa = True
352
    #
353
    x = functionSa.variables()[0] # Actual variable name can be anything.
354
    # Scaled function: [1=,2] -> [1,2].
355
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
356
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
357
                slz_compute_scaled_function(functionSa,                       \
358
                                            lowerBoundSa,                     \
359
                                            upperBoundSa,                     \
360
                                            floatingPointPrecSa)
361
    #
362
    print "Approximation precision: ", RR(approxPrecSa)
363
    # Prepare the arguments for the Taylor expansion computation with Sollya.
364
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
365
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
366
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
367
                                                  scaledUpperBoundSa)
368
    # Compute the first Taylor expansion.
369
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
370
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
371
                                        scaledLowerBoundSa, scaledUpperBoundSa,
372
                                        approxPrecSa, internalSollyaPrecSa)
373
    if polySo is None:
374
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
375
        if precChangedSa:
376
            pobyso_set_prec_so_so(currentSollyaPrecSo)
377
            sollya_lib_clear_obj(currentSollyaPrecSo)
378
        sollya_lib_clear_obj(functionSo)
379
        sollya_lib_clear_obj(degreeSo)
380
        sollya_lib_clear_obj(scaledBoundsSo)
381
        return None
382
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
383
                                              upperBoundSa.parent().precision()))
384
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
385
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
386
    #print "First approximation error:", errorSa
387
    # If the error and interval are OK a the first try, just return.
388
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
389
        # Change variable stuff in Sollya x -> x0-x.
390
        changeVarExpressionSo = sollya_lib_build_function_sub( \
391
                              sollya_lib_build_function_free_variable(), \
392
                              sollya_lib_copy_obj(intervalCenterSo))
393
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
394
        sollya_lib_clear_obj(changeVarExpressionSo)
395
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
396
                            intervalCenterSo, maxErrorSo))
397
        if internalSollyaPrecSa != currentSollyaPrecSa:
398
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
399
        sollya_lib_clear_obj(currentSollyaPrecSo)
400
        sollya_lib_clear_obj(functionSo)
401
        sollya_lib_clear_obj(degreeSo)
402
        sollya_lib_clear_obj(scaledBoundsSo)
403
        #print "Approximation error:", errorSa
404
        return resultArray
405
    # The returned interval upper bound does not reach the requested upper
406
    # upper bound: compute the next upper bound.
407
    # The following ratio is always >= 1
408
    currentErrorRatio = approxPrecSa / errorSa
409
    # Starting point for the next upper bound.
410
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
411
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
412
    # Compute the increment. 
413
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
414
        currentScaledUpperBoundSa += \
415
                        currentErrorRatio * boundsWidthSa * 2
416
    else:  # [1, 1.5]
417
        currentScaledUpperBoundSa += \
418
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
419
    # Take into account the original interval upper bound.                     
420
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
421
        currentScaledUpperBoundSa = scaledUpperBoundSa
422
    # Compute the other expansions.
423
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
424
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
425
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
426
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
427
                                            currentScaledLowerBoundSa, 
428
                                            currentScaledUpperBoundSa, 
429
                                            approxPrecSa, 
430
                                            internalSollyaPrecSa)
431
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
432
        if  errorSa < approxPrecSa:
433
            # Change variable stuff
434
            #print "Approximation error:", errorSa
435
            changeVarExpressionSo = sollya_lib_build_function_sub(
436
                                    sollya_lib_build_function_free_variable(), 
437
                                    sollya_lib_copy_obj(intervalCenterSo))
438
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
439
            sollya_lib_clear_obj(changeVarExpressionSo)
440
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
441
                                intervalCenterSo, maxErrorSo))
442
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
443
        # Compute the next upper bound.
444
        # The following ratio is always >= 1
445
        currentErrorRatio = approxPrecSa / errorSa
446
        # Starting point for the next upper bound.
447
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
448
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
449
        # Compute the increment. 
450
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
451
            currentScaledUpperBoundSa += \
452
                            currentErrorRatio * boundsWidthSa * 2
453
        else:  # [1, 1.5]
454
            currentScaledUpperBoundSa += \
455
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
456
        #print "currentErrorRatio:", currentErrorRatio
457
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
458
        # Test for insufficient precision.
459
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
460
            print "Can't shrink the interval anymore!"
461
            print "You should consider increasing the Sollya internal precision"
462
            print "or the polynomial degree."
463
            print "Giving up!"
464
            if internalSollyaPrecSa != currentSollyaPrecSa:
465
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
466
            sollya_lib_clear_obj(currentSollyaPrecSo)
467
            sollya_lib_clear_obj(functionSo)
468
            sollya_lib_clear_obj(degreeSo)
469
            sollya_lib_clear_obj(scaledBoundsSo)
470
            return None
471
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
472
            currentScaledUpperBoundSa = scaledUpperBoundSa
473
    if internalSollyaPrecSa > currentSollyaPrecSa:
474
        pobyso_set_prec_so_so(currentSollyaPrecSo)
475
    sollya_lib_clear_obj(currentSollyaPrecSo)
476
    sollya_lib_clear_obj(functionSo)
477
    sollya_lib_clear_obj(degreeSo)
478
    sollya_lib_clear_obj(scaledBoundsSo)
479
    return(resultArray)
480
# End slz_get_intervals_and_polynomials
481

    
482

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

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

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

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

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

    
626

    
627
print "\t...sageSLZ loaded"