Statistiques
| Révision :

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

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

1
"""
2
module:: sageSLZ.sage
3

    
4
Sage core function needed for the implementation of SLZ.
5

    
6
Created on 2013-08
7

    
8
moduleauthor:: S.T.
9
"""
10
print "sageSLZ loading..."
11
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa, 
12
                                        upperBoundSa, approxPrecSa, 
13
                                        sollyaPrecSa=None):
14
    """
15
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
16
    a polynomial that approximates the function on a an interval starting
17
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
18
    approximates with the expected precision.
19
    The interval upper bound is lowered until the expected approximation 
20
    precision is reached.
21
    The polynomial, the bounds, the center of the interval and the error
22
    are returned.
23
    """
24
    RRR = lowerBoundSa.parent()
25
    intervalShrinkConstFactorSa = RRR('0.5')
26
    absoluteErrorTypeSo = pobyso_absolute_so_so()
27
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
28
    currentUpperBoundSa = upperBoundSa
29
    currentLowerBoundSa = lowerBoundSa
30
    # What we want here is the polynomial without the variable change, 
31
    # since our actual variable will be x-intervalCenter defined over the 
32
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
33
    (polySo, intervalCenterSo, maxErrorSo) = \
34
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
35
                                                    currentRangeSo, 
36
                                                    absoluteErrorTypeSo)
37
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
38
    while maxErrorSa > approxPrecSa:
39
        #print "++Approximation error:", maxErrorSa
40
        sollya_lib_clear_obj(maxErrorSo)
41
        sollya_lib_clear_obj(polySo)
42
        sollya_lib_clear_obj(intervalCenterSo)
43
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
44
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
45
        #errorRatioSa = approxPrecSa/maxErrorSa
46
        #print "Error ratio: ", errorRatioSa
47
        if shrinkFactorSa > intervalShrinkConstFactorSa:
48
            actualShrinkFactorSa = intervalShrinkConstFactorSa
49
            #print "Fixed"
50
        else:
51
            actualShrinkFactorSa = shrinkFactorSa
52
            #print "Computed",shrinkFactorSa,maxErrorSa
53
            #print shrinkFactorSa, maxErrorSa
54
        #print "Shrink factor", actualShrinkFactorSa
55
        currentUpperBoundSa = currentLowerBoundSa + \
56
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
57
                                   actualShrinkFactorSa
58
        #print "Current upper bound:", currentUpperBoundSa
59
        sollya_lib_clear_obj(currentRangeSo)
60
        sollya_lib_clear_obj(polySo)
61
        if currentUpperBoundSa <= currentLowerBoundSa or \
62
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
63
            sollya_lib_clear_obj(absoluteErrorTypeSo)
64
            print "Can't find an interval."
65
            print "Use either or both a higher polynomial degree or a higher",
66
            print "internal precision."
67
            print "Aborting!"
68
            return (None, None, None, None)
69
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
70
                                                      currentUpperBoundSa)
71
        # print "New interval:",
72
        # pobyso_autoprint(currentRangeSo)
73
        (polySo, intervalCenterSo, maxErrorSo) = \
74
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
75
                                                        currentRangeSo, 
76
                                                        absoluteErrorTypeSo)
77
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
78
        #print "Max errorSo:",
79
        #pobyso_autoprint(maxErrorSo)
80
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
81
        #print "Max errorSa:", maxErrorSa
82
        #print "Sollya prec:",
83
        #pobyso_autoprint(sollya_lib_get_prec(None))
84
    sollya_lib_clear_obj(absoluteErrorTypeSo)
85
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
86
# End slz_compute_polynomial_and_interval
87

    
88
def slz_compute_reduced_polynomials(reducedMatrix,
89
                                    knownMonomials,
90
                                    var1Bound,
91
                                    var2Bound):
92
    """
93
    From a reduced matrix, holding the coefficients, from a monomials list,
94
    from the bounds of each variable, compute the corresponding polynomials
95
    scaled back by dividing by the "right" powers of the variables bounds.
96
    
97
    The elements in knownMonomials must be of the "right" polynomial type.
98
    They set the polynomial type of the output polynomials list.
99
    """
100
    
101
    # TODO: check input arguments.
102
    if len(knownMonomials) == 0:
103
        return []
104
    # Search in knowMonomials until we find a bivariate one, otherwise
105
    # the call to variables does not give the expected result.
106
    monomialIndex = 1
107
    while len(knownMonomials[monomialIndex].variables()) != 2 :
108
        monomialIndex +=1
109
    (var1, var2) = knownMonomials[monomialIndex].variables()[0:2]
110
    #print "Variable 1:", var1
111
    #print "Variable 2:", var2
112
    reducedPolynomials = []
113
    currentPolynomial = 0
114
    for matrixRow in reducedMatrix.rows():
115
        currentPolynomial = 0
116
        for colIndex in xrange(0, len(knownMonomials)):
117
            currentCoefficient = matrixRow[colIndex]
118
            #print knownMonomials[colIndex]
119
            currentMonomial = knownMonomials[colIndex]
120
            #print "Monomial as multivariate polynomial:", \
121
            currentMonomial, type(currentMonomial)
122
            degreeInVar1 = currentMonomial.degree(var1)
123
            #print "Degree in var", var1, ":", degreeInVar1
124
            degreeInVar2 = currentMonomial.degree(var2)
125
            #print "Degree in var", var2, ":", degreeInVar2
126
            if degreeInVar1 != 0:
127
                currentCoefficient  /= (var1Bound^degreeInVar1)
128
            if degreeInVar2 != 0:
129
                currentCoefficient /= (var2Bound^degreeInVar2)
130
            #print "Current reduced monomial:", (currentCoefficient * \
131
            #                                    currentMonomial)
132
            currentPolynomial += (currentCoefficient * currentMonomial)
133
        #print "Type of the current polynomial:", type(currentPolynomial)
134
        reducedPolynomials.append(currentPolynomial)
135
    return reducedPolynomials 
136
# End slz_compute_reduced_polynomials.
137

    
138
def slz_compute_scaled_function(functionSa, \
139
                                      lowerBoundSa, \
140
                                      upperBoundSa, \
141
                                      floatingPointPrecSa):
142
    """
143
    From a function, compute the scaled function whose domain
144
    is included in [1, 2) and whose image is also included in [1,2).
145
    Return a tuple: 
146
    [0]: the scaled function
147
    [1]: the scaled domain lower bound
148
    [2]: the scaled domain upper bound
149
    [3]: the scaled image lower bound
150
    [4]: the scaled image upper bound
151
    """
152
    x = functionSa.variables()[0]
153
    # Reassert f as a function (an not a mere expression).
154
    
155
    # Scalling the domain -> [1,2[.
156
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
157
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
158
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
159
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
160
    print "domainScalingExpression for argument :", domainScalingExpressionSa
161
    print "f: ", f
162
    ff = f.subs({x : domainScalingExpressionSa})
163
    #ff = f.subs_expr(x==domainScalingExpressionSa)
164
    domainScalingFunction(x) = invDomainScalingExpressionSa
165
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
166
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
167
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
168
    #
169
    # Scalling the image -> [1,2[.
170
    flbSa = f(lowerBoundSa).n()
171
    fubSa = f(upperBoundSa).n()
172
    if flbSa <= fubSa: # Increasing
173
        imageBinadeBottomSa = floor(flbSa.log2())
174
    else: # Decreasing
175
        imageBinadeBottomSa = floor(fubSa.log2())
176
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
177
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
178
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
179
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
180
    iis = invImageScalingExpressionSa.function(x)
181
    fff = iis.subs({x:ff})
182
    print "fff:", fff,
183
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
184
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
185
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
186

    
187
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
188
    # Create a polynomial over the rationals.
189
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
190
    return(polynomialRing(polyOfFloat))
191
# End slz_float_poly_of_float_to_rat_poly_of_rat.
192

    
193
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
194
                                      lowerBoundSa, 
195
                                      upperBoundSa, floatingPointPrecSa, 
196
                                      internalSollyaPrecSa, approxPrecSa):
197
    """
198
    Under the assumption that:
199
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
200
    - lowerBound and upperBound belong to the same binade.
201
    from a:
202
    - function;
203
    - a degree
204
    - a pair of bounds;
205
    - the floating-point precision we work on;
206
    - the internal Sollya precision;
207
    - the requested approximation error
208
    The initial interval is, possibly, splitted into smaller intervals.
209
    It return a list of tuples, each made of:
210
    - a first polynomial (without the changed variable f(x) = p(x-x0));
211
    - a second polynomial (with a changed variable f(x) = q(x))
212
    - the approximation interval;
213
    - the center, x0, of the interval;
214
    - the corresponding approximation error.
215
    TODO: fix endless looping for some parameters sets.
216
    """
217
    # Set Sollya to the necessary internal precision.
218
    currentSollyaPrecSo = pobyso_get_prec_so()
219
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
220
    if internalSollyaPrecSa > currentSollyaPrecSa:
221
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
222
    #
223
    x = functionSa.variables()[0] # Actual variable name can be anything.
224
    # Scaled function: [1=,2] -> [1,2].
225
    (fff, scaledLowerBoundSa, scaledUpperBoundSa, \
226
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) = \
227
                slz_compute_scaled_function(functionSa, \
228
                                            lowerBoundSa, \
229
                                            upperBoundSa, \
230
                                            floatingPointPrecSa)
231
    #
232
    resultArray = []
233
    #
234
    print "Approximation precision: ", RR(approxPrecSa)
235
    # Prepare the arguments for the Taylor expansion computation with Sollya.
236
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
237
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
238
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
239
                                                  scaledUpperBoundSa)
240
    # Compute the first Taylor expansion.
241
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
242
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
243
                                        scaledLowerBoundSa, scaledUpperBoundSa,
244
                                        approxPrecSa, internalSollyaPrecSa)
245
    if polySo is None:
246
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
247
        if internalSollyaPrecSa != currentSollyaPrecSa:
248
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
249
        return None
250
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
251
                                              upperBoundSa.parent().precision()))
252
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
253
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
254
    #print "First approximation error:", errorSa
255
    # If the error and interval are OK a the first try, just return.
256
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
257
        # Change variable stuff in Sollya x -> x0-x.
258
        changeVarExpressionSo = sollya_lib_build_function_sub( \
259
                              sollya_lib_build_function_free_variable(), \
260
                              sollya_lib_copy_obj(intervalCenterSo))
261
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
262
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
263
                            intervalCenterSo, maxErrorSo))
264
        if internalSollyaPrecSa != currentSollyaPrecSa:
265
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
266
        sollya_lib_clear_obj(functionSo)
267
        sollya_lib_clear_obj(degreeSo)
268
        sollya_lib_clear_obj(scaledBoundsSo)
269
        #print "Approximation error:", errorSa
270
        return resultArray
271
    # Compute the next upper bound.
272
    # The following ratio is always >= 1
273
    currentErrorRatio = approxPrecSa / errorSa
274
    # Starting point for the next upper bound.
275
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
276
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
277
    # Compute the increment. 
278
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
279
        currentScaledUpperBoundSa += \
280
                        currentErrorRatio * boundsWidthSa * 2
281
    else:  # [1, 1.5]
282
        currentScaledUpperBoundSa += \
283
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
284
    # Take into account the original interval upper bound.                     
285
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
286
        currentScaledUpperBoundSa = scaledUpperBoundSa
287
    # Compute the other expansions.
288
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
289
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
290
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
291
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
292
                                            currentScaledLowerBoundSa, 
293
                                            currentScaledUpperBoundSa, 
294
                                            approxPrecSa, 
295
                                            internalSollyaPrecSa)
296
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
297
        if  errorSa < approxPrecSa:
298
            # Change variable stuff
299
            #print "Approximation error:", errorSa
300
            changeVarExpressionSo = sollya_lib_build_function_sub(
301
                                    sollya_lib_build_function_free_variable(), 
302
                                    sollya_lib_copy_obj(intervalCenterSo))
303
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
304
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
305
                                intervalCenterSo, maxErrorSo))
306
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
307
        # Compute the next upper bound.
308
        # The following ratio is always >= 1
309
        currentErrorRatio = approxPrecSa / errorSa
310
        # Starting point for the next upper bound.
311
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
312
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
313
        # Compute the increment. 
314
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
315
            currentScaledUpperBoundSa += \
316
                            currentErrorRatio * boundsWidthSa * 2
317
        else:  # [1, 1.5]
318
            currentScaledUpperBoundSa += \
319
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
320
        #print "currentErrorRatio:", currentErrorRatio
321
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
322
        # Test for insufficient precision.
323
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
324
            print "Can't shrink the interval anymore!"
325
            print "You should consider increasing the Sollya internal precision"
326
            print "or the polynomial degree."
327
            print "Giving up!"
328
            if internalSollyaPrecSa != currentSollyaPrecSa:
329
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
330
            sollya_lib_clear_obj(functionSo)
331
            sollya_lib_clear_obj(degreeSo)
332
            sollya_lib_clear_obj(scaledBoundsSo)
333
            return None
334
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
335
            currentScaledUpperBoundSa = scaledUpperBoundSa
336
    sollya_lib_clear_obj(functionSo)
337
    sollya_lib_clear_obj(degreeSo)
338
    sollya_lib_clear_obj(scaledBoundsSo)
339
    if internalSollyaPrecSa > currentSollyaPrecSa:
340
        pobyso_set_prec_so_so(currentSollyaPrecSo)
341
    return(resultArray)
342
# End slz_get_intervals_and_polynomials
343

    
344

    
345
def slz_interval_scaling_expression(boundsInterval, expVar):
346
    """
347
    Compute the scaling expression to map an interval that span only
348
    a binade to [1, 2) and the inverse expression as well.
349
    Not very sure that the transformation makes sense for negative numbers.
350
    """
351
    # The scaling offset is only used for negative numbers.
352
    if abs(boundsInterval.endpoints()[0]) < 1:
353
        if boundsInterval.endpoints()[0] >= 0:
354
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
355
            invScalingCoeff = 1/scalingCoeff
356
            return((scalingCoeff * expVar, 
357
                    invScalingCoeff * expVar))
358
        else:
359
            scalingCoeff = \
360
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
361
            scalingOffset = -3 * scalingCoeff
362
            return((scalingCoeff * expVar + scalingOffset,
363
                    1/scalingCoeff * expVar + 3))
364
    else: 
365
        if boundsInterval.endpoints()[0] >= 0:
366
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
367
            scalingOffset = 0
368
            return((scalingCoeff * expVar, 
369
                    1/scalingCoeff * expVar))
370
        else:
371
            scalingCoeff = \
372
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
373
            scalingOffset =  -3 * scalingCoeff
374
            #scalingOffset = 0
375
            return((scalingCoeff * expVar + scalingOffset,
376
                    1/scalingCoeff * expVar + 3))
377

    
378
   
379
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
380
    """
381
    Compute the Sage version of the Taylor polynomial and it's
382
    companion data (interval, center...)
383
    The input parameter is a five elements tuple:
384
    - [0]: the polyomial (without variable change), as polynomial over a
385
           real ring;
386
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
387
           over a real ring;
388
    - [2]: the interval (as Sollya range);
389
    - [3]: the interval center;
390
    - [4]: the approximation error. 
391
    
392
    The function return a 5 elements tuple: formed with all the 
393
    input elements converted into their Sollya counterpart.
394
    """
395
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
396
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
397
    intervalSa = \
398
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
399
    centerSa = \
400
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
401
    errorSa = \
402
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
403
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
404
    # End slz_interval_and_polynomial_to_sage
405

    
406
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
407
                                                precision,
408
                                                targetHardnessToRound,
409
                                                variable1,
410
                                                variable2):
411
    """
412
    Creates a new multivariate polynomial with integer coefficients for use
413
     with the Coppersmith method.
414
    A the same time it computes :
415
    - 2^K (N);
416
    - 2^k (bound on the second variable)
417
    - lcm
418

    
419
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
420
                         variables.
421
    :param precision: the precision of the floating-point coefficients.
422
    :param targetHardnessToRound: the hardness to round we want to check.
423
    :param variable1: the first variable of the polynomial (an expression).
424
    :param variable2: the second variable of the polynomial (an expression).
425
    
426
    :returns: a 4 elements tuple:
427
                - the polynomial;
428
                - the modulus (N);
429
                - the t bound;
430
                - the lcm used to compute the integral coefficients and the 
431
                  module.
432
    """
433
    # Create a new integer polynomial ring.
434
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
435
    # Coefficients are issued in the increasing power order.
436
    ratPolyCoefficients = ratPolyOfInt.coefficients()
437
    # Print the reversed list for debugging.
438
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
439
    # Build the list of number we compute the lcm of.
440
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
441
    coefficientDenominators.append(2^precision)
442
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
443
    leastCommonMultiple = lcm(coefficientDenominators)
444
    # Compute the expression corresponding to the new polynomial
445
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
446
    #print coefficientNumerators
447
    polynomialExpression = 0
448
    power = 0
449
    # Iterate over two lists at the same time, stop when the shorter is
450
    # exhausted.
451
    for numerator, denominator in \
452
                        zip(coefficientNumerators, coefficientDenominators):
453
        multiplicator = leastCommonMultiple / denominator 
454
        newCoefficient = numerator * multiplicator
455
        polynomialExpression += newCoefficient * variable1^power
456
        power +=1
457
    polynomialExpression += - variable2
458
    return (IP(polynomialExpression),
459
            leastCommonMultiple / 2^precision, # 2^K or N.
460
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
461
            leastCommonMultiple) # If we want to make test computations.
462
        
463
# End slz_ratPoly_of_int_to_poly_for_coppersmith
464

    
465
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
466
                                          precision):
467
    """
468
    Makes a variable substitution into the input polynomial so that the output
469
    polynomial can take integer arguments.
470
    All variables of the input polynomial "have precision p". That is to say
471
    that they are rationals with denominator == 2^(precision - 1): 
472
    x = y/2^(precision - 1).
473
    We "incorporate" these denominators into the coefficients with, 
474
    respectively, the "right" power.
475
    """
476
    polynomialField = ratPolyOfRat.parent()
477
    polynomialVariable = ratPolyOfRat.variables()[0]
478
    #print "The polynomial field is:", polynomialField
479
    return \
480
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
481
                                   polynomialVariable/2^(precision-1)}))
482
    
483
    # Return a tuple:
484
    # - the bivariate integer polynomial in (i,j);
485
    # - 2^K
486
# End slz_rat_poly_of_rat_to_rat_poly_of_int
487

    
488
print "\t...sageSLZ loaded"