Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (23,27 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
                                    var1,
91
                                    var1Bound,
92
                                    var2,
93
                                    var2Bound):
94
    """
95
    From a reduced matrix, holding the coefficients, from a monomials list,
96
    from the bounds of each variable, compute the corresponding polynomials
97
    scaled back by dividing by the "right" powers of the variables bounds.
98
    
99
    The elements in knownMonomials must be of the "right" polynomial type.
100
    They set the polynomial type of the output polynomials list.
101
    """
102
    
103
    # TODO: check input arguments.
104
    reducedPolynomials = []
105
    #print "type var1:", type(var1), " - type var2:", type(var2)
106
    for matrixRow in reducedMatrix.rows():
107
        currentPolynomial = 0
108
        for colIndex in xrange(0, len(knownMonomials)):
109
            currentCoefficient = matrixRow[colIndex]
110
            if currentCoefficient != 0:
111
                #print "Current coefficient:", currentCoefficient
112
                currentMonomial = knownMonomials[colIndex]
113
                parentRing = currentMonomial.parent()
114
                #print "Monomial as multivariate polynomial:", \
115
                #currentMonomial, type(currentMonomial)
116
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
117
                #print "Degree in var", var1, ":", degreeInVar1
118
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
119
                #print "Degree in var", var2, ":", degreeInVar2
120
                if degreeInVar1 > 0:
121
                    currentCoefficient = \
122
                        currentCoefficient / var1Bound^degreeInVar1
123
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
124
                    #print "Current coefficient(1)", currentCoefficient
125
                if degreeInVar2 > 0:
126
                    currentCoefficient = \
127
                        currentCoefficient / var2Bound^degreeInVar2
128
                    #print "Current coefficient(2)", currentCoefficient
129
                #print "Current reduced monomial:", (currentCoefficient * \
130
                #                                    currentMonomial)
131
                currentPolynomial += (currentCoefficient * currentMonomial)
132
                #print "Current polynomial:", currentPolynomial
133
            # End if
134
        # End for colIndex.
135
        #print "Type of the current polynomial:", type(currentPolynomial)
136
        reducedPolynomials.append(currentPolynomial)
137
    return reducedPolynomials 
138
# End slz_compute_reduced_polynomials.
139

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

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

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

    
346

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

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

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

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

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

    
490
print "\t...sageSLZ loaded"