Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (22,88 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
    """
99
    
100
    # TODO: check input arguments.
101
    if len(knownMonomials) == 0:
102
        return []
103
    # Search in knowMonomials until we find a bivariate one, otherwise
104
    # the call to variables does not give the expected result.
105
    monomialIndex = 1
106
    while len(knownMonomials[monomialIndex].variables()) != 2 :
107
        monomialIndex +=1
108
    (var1, var2) = knownMonomials[monomialIndex].variables()[0:2]
109
    #print "Variable 1:", var1
110
    #print "Variable 2:", var2
111
    reducedPolynomials = []
112
    currentPolynomial = 0
113
    for matrixRow in reducedMatrix.rows():
114
        currentPolynomial = 0
115
        for colIndex in xrange(0, len(knownMonomials)):
116
            currentCoefficient = matrixRow[colIndex]
117
            #print knownMonomials[colIndex]
118
            currentMonomial = knownMonomials[colIndex]
119
            #print "Monomial as multivariate polynomial:", \
120
            currentMonomial, type(currentMonomial)
121
            degreeInVar1 = currentMonomial.degree(var1)
122
            #print "Degree in var", var1, ":", degreeInVar1
123
            degreeInVar2 = currentMonomial.degree(var2)
124
            #print "Degree in var", var2, ":", degreeInVar2
125
            if degreeInVar1 != 0:
126
                currentCoefficient  /= (var1Bound^degreeInVar1)
127
            if degreeInVar2 != 0:
128
                currentCoefficient /= (var2Bound^degreeInVar2)
129
            #print "Current reduced monomial:", (currentCoefficient * \
130
            #                                    currentMonomial)
131
            currentPolynomial += (currentCoefficient * currentMonomial)
132
        #print "Type of the current polynomial:", type(currentPolynomial)
133
        reducedPolynomials.append(currentPolynomial)
134
    return reducedPolynomials 
135
# End slz_compute_reduced_polynomials.
136

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

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

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

    
343

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

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

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

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

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

    
486
print "\t...sageSLZ loaded"