Statistiques
| Révision :

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

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

    
90
# End slz_check_htr_value.
91

    
92
#
93
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
94
    """
95
    For given "real number", compute the bounds of the binade it belongs to.
96
    
97
    NOTE::
98
        When number >= 2^(emax+1), we return the "fake" binade 
99
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
100
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
101
        this case from that of "really" invalid arguments.
102
        
103
    """
104
    # Check the parameters.
105
    # RealNumbers or RealNumber offspring only.
106
    # The execption construction is necessary since not all objects have
107
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
108
    try:
109
        classTree = [number.__class__] + number.mro()
110
        if not sage.rings.real_mpfr.RealNumber in classTree:
111
            return None
112
    except AttributeError:
113
        return None
114
    # Non zero negative integers only for emin.
115
    if emin >= 0 or int(emin) != emin:
116
        return None
117
    # Non zero positive integers only for emax.
118
    if emax <= 0 or int(emax) != emax:
119
        return None
120
    precision = number.precision()
121
    RF  = RealField(precision)
122
    if number == 0:
123
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
124
    # A more precise RealField is needed to avoid unwanted rounding effects
125
    # when computing number.log2().
126
    RRF = RealField(max(2048, 2 * precision))
127
    # number = 0 special case, the binade bounds are 
128
    # [0, 2^emin - 2^(emin-precision)]
129
    # Begin general case
130
    l2 = RRF(number).abs().log2()
131
    # Another special one: beyond largest representable -> "Fake" binade.
132
    if l2 >= emax + 1:
133
        if number > 0:
134
            return (RF(2^(emax+1)), RF(+infinity) )
135
        else:
136
            return (RF(-infinity), -RF(2^(emax+1)))
137
    offset = int(l2)
138
    # number.abs() >= 1.
139
    if l2 >= 0:
140
        if number >= 0:
141
            lb = RF(2^offset)
142
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
143
        else: #number < 0
144
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
145
            ub = -RF(2^offset)
146
    else: # log2 < 0, number.abs() < 1.
147
        if l2 < emin: # Denormal
148
           # print "Denormal:", l2
149
            if number >= 0:
150
                lb = RF(0)
151
                ub = RF(2^(emin)) - RF(2^(emin-precision))
152
            else: # number <= 0
153
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
154
                ub = RF(0)
155
        elif l2 > emin: # Normal number other than +/-2^emin.
156
            if number >= 0:
157
                if int(l2) == l2:
158
                    lb = RF(2^(offset))
159
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
160
                else:
161
                    lb = RF(2^(offset-1))
162
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
163
            else: # number < 0
164
                if int(l2) == l2: # Binade limit.
165
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
166
                    ub = -RF(2^(offset))
167
                else:
168
                    lb = -RF(2^(offset) - 2^(-precision+offset))
169
                    ub = -RF(2^(offset-1))
170
        else: # l2== emin, number == +/-2^emin
171
            if number >= 0:
172
                lb = RF(2^(offset))
173
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
174
            else: # number < 0
175
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
176
                ub = -RF(2^(offset))
177
    return (lb, ub)
178
# End slz_compute_binade_bounds
179
#
180
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
181
                                                 alpha,
182
                                                 N,
183
                                                 iBound,
184
                                                 tBound):
185
    """
186
    For a given set of arguments (see below), compute a list
187
    of "reduced polynomials" that could be used to compute roots
188
    of the inputPolynomial.
189
    INPUT:
190
    
191
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
192
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
193
    - "N" -- the modulus;
194
    - "iBound" -- the bound on the first variable;
195
    - "tBound" -- the bound on the second variable.
196
    
197
    OUTPUT:
198
    
199
    A list of bivariate integer polynomial obtained using the Coppersmith
200
    algorithm. The polynomials correspond to the rows of the LLL-reduce
201
    reduced base that comply with the Coppersmith condition.
202
    """
203
    # Arguments check.
204
    if iBound == 0 or tBound == 0:
205
        return ()
206
    # End arguments check.
207
    nAtAlpha = N^alpha
208
    ## Building polynomials for matrix.
209
    polyRing   = inputPolynomial.parent()
210
    # Whatever the 2 variables are actually called, we call them
211
    # 'i' and 't' in all the variable names.
212
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
213
    #print polyVars[0], type(polyVars[0])
214
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
215
                                              tVariable:tVariable * tBound})
216
    polynomialsList = \
217
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
218
                                             alpha,
219
                                             N,
220
                                             iBound,
221
                                             tBound,
222
                                             0)
223
    #print "Polynomials list:", polynomialsList
224
    ## Building the proto matrix.
225
    knownMonomials = []
226
    protoMatrix    = []
227
    for poly in polynomialsList:
228
        spo_add_polynomial_coeffs_to_matrix_row(poly,
229
                                                knownMonomials,
230
                                                protoMatrix,
231
                                                0)
232
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
233
    #print matrixToReduce
234
    ## Reduction and checking.
235
    reducedMatrix = matrixToReduce.LLL(fp='fp')
236
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
237
    if not isLLLReduced:
238
        return ()
239
    monomialsCount     = len(knownMonomials)
240
    monomialsCountSqrt = sqrt(monomialsCount)
241
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
242
    #print reducedMatrix
243
    ## Check the Coppersmith condition for each row and build the reduced 
244
    #  polynomials.
245
    ccReducedPolynomialsList = []
246
    for row in reducedMatrix.rows():
247
        l2Norm = row.norm(2)
248
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
249
            #print (l2Norm * monomialsCountSqrt).n()
250
            #print l2Norm.n()
251
            ccReducedPolynomial = \
252
                slz_compute_reduced_polynomial(row,
253
                                               knownMonomials,
254
                                               iVariable,
255
                                               iBound,
256
                                               tVariable,
257
                                               tBound)
258
            if not ccReducedPolynomial is None:
259
                ccReducedPolynomialsList.append(ccReducedPolynomial)
260
        else:
261
            #print l2Norm.n() , ">", nAtAlpha
262
            pass
263
    if len(ccReducedPolynomialsList) < 2:
264
        print "Less than 2 Coppersmith condition compliant vectors."
265
        return ()
266
    
267
    #print ccReducedPolynomialsList
268
    return ccReducedPolynomialsList
269
# End slz_compute_coppersmith_reduced_polynomials
270

    
271
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
272
                                                 alpha,
273
                                                 N,
274
                                                 iBound,
275
                                                 tBound):
276
    """
277
    For a given set of arguments (see below), compute the polynomial modular 
278
    roots, if any.
279
    
280
    """
281
    # Arguments check.
282
    if iBound == 0 or tBound == 0:
283
        return set()
284
    # End arguments check.
285
    nAtAlpha = N^alpha
286
    ## Building polynomials for matrix.
287
    polyRing   = inputPolynomial.parent()
288
    # Whatever the 2 variables are actually called, we call them
289
    # 'i' and 't' in all the variable names.
290
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
291
    ccReducedPolynomialsList = \
292
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
293
                                                     alpha,
294
                                                     N,
295
                                                     iBound,
296
                                                     tBound)
297
    if len(ccReducedPolynomialsList) == 0:
298
        return set()   
299
    ## Create the valid (poly1 and poly2 are algebraically independent) 
300
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
301
    # Try to mix and match all the polynomial pairs built from the 
302
    # ccReducedPolynomialsList to obtain non zero resultants.
303
    resultantsInITuplesList = []
304
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
305
        for polyInnerIndex in xrange(polyOuterIndex+1, 
306
                                     len(ccReducedPolynomialsList)):
307
            # Compute the resultant in resultants in the
308
            # first variable (is it the optimal choice?).
309
            resultantInI = \
310
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
311
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
312
            #print "Resultant", resultantInI
313
            # Test algebraic independence.
314
            if not resultantInI.is_zero():
315
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
316
                                                 ccReducedPolynomialsList[polyInnerIndex],
317
                                                 resultantInI))
318
    # If no non zero resultant was found: we can't get no algebraically 
319
    # independent polynomials pair. Give up!
320
    if len(resultantsInITuplesList) == 0:
321
        return set()
322
    #print resultantsInITuplesList
323
    # Compute the roots.
324
    Zi = ZZ[str(iVariable)]
325
    Zt = ZZ[str(tVariable)]
326
    polynomialRootsSet = set()
327
    # First, solve in the second variable since resultants are in the first
328
    # variable.
329
    for resultantInITuple in resultantsInITuplesList:
330
        tRootsList = Zt(resultantInITuple[2]).roots()
331
        # For each tRoot, compute the corresponding iRoots and check 
332
        # them in the input polynomial.
333
        for tRoot in tRootsList:
334
            #print "tRoot:", tRoot
335
            # Roots returned by root() are (value, multiplicity) tuples.
336
            iRootsList = \
337
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
338
            print iRootsList
339
            # The iRootsList can be empty, hence the test.
340
            if len(iRootsList) != 0:
341
                for iRoot in iRootsList:
342
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
343
                    # polyEvalModN must be an integer.
344
                    if polyEvalModN == int(polyEvalModN):
345
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
346
    return polynomialRootsSet
347
# End slz_compute_integer_polynomial_modular_roots.
348
#
349
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
350
                                                 alpha,
351
                                                 N,
352
                                                 iBound,
353
                                                 tBound):
354
    """
355
    For a given set of arguments (see below), compute the polynomial modular 
356
    roots, if any.
357
    This version differs in the way resultants are computed.   
358
    """
359
    # Arguments check.
360
    if iBound == 0 or tBound == 0:
361
        return set()
362
    # End arguments check.
363
    nAtAlpha = N^alpha
364
    ## Building polynomials for matrix.
365
    polyRing   = inputPolynomial.parent()
366
    # Whatever the 2 variables are actually called, we call them
367
    # 'i' and 't' in all the variable names.
368
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
369
    #print polyVars[0], type(polyVars[0])
370
    ccReducedPolynomialsList = \
371
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
372
                                                     alpha,
373
                                                     N,
374
                                                     iBound,
375
                                                     tBound)
376
    if len(ccReducedPolynomialsList) == 0:
377
        return set()   
378
    ## Create the valid (poly1 and poly2 are algebraically independent) 
379
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
380
    # Try to mix and match all the polynomial pairs built from the 
381
    # ccReducedPolynomialsList to obtain non zero resultants.
382
    resultantsInTTuplesList = []
383
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
384
        for polyInnerIndex in xrange(polyOuterIndex+1, 
385
                                     len(ccReducedPolynomialsList)):
386
            # Compute the resultant in resultants in the
387
            # first variable (is it the optimal choice?).
388
            resultantInT = \
389
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
390
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
391
            #print "Resultant", resultantInT
392
            # Test algebraic independence.
393
            if not resultantInT.is_zero():
394
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
395
                                                 ccReducedPolynomialsList[polyInnerIndex],
396
                                                 resultantInT))
397
    # If no non zero resultant was found: we can't get no algebraically 
398
    # independent polynomials pair. Give up!
399
    if len(resultantsInTTuplesList) == 0:
400
        return set()
401
    #print resultantsInITuplesList
402
    # Compute the roots.
403
    Zi = ZZ[str(iVariable)]
404
    Zt = ZZ[str(tVariable)]
405
    polynomialRootsSet = set()
406
    # First, solve in the second variable since resultants are in the first
407
    # variable.
408
    for resultantInTTuple in resultantsInTTuplesList:
409
        iRootsList = Zi(resultantInTTuple[2]).roots()
410
        # For each iRoot, compute the corresponding tRoots and check 
411
        # them in the input polynomial.
412
        for iRoot in iRootsList:
413
            #print "iRoot:", iRoot
414
            # Roots returned by root() are (value, multiplicity) tuples.
415
            tRootsList = \
416
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
417
            print tRootsList
418
            # The tRootsList can be empty, hence the test.
419
            if len(tRootsList) != 0:
420
                for tRoot in tRootsList:
421
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
422
                    # polyEvalModN must be an integer.
423
                    if polyEvalModN == int(polyEvalModN):
424
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
425
    return polynomialRootsSet
426
# End slz_compute_integer_polynomial_modular_roots_2.
427
#
428
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa, 
429
                                        upperBoundSa, approxPrecSa, 
430
                                        sollyaPrecSa=None):
431
    """
432
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
433
    a polynomial that approximates the function on a an interval starting
434
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
435
    approximates with the expected precision.
436
    The interval upper bound is lowered until the expected approximation 
437
    precision is reached.
438
    The polynomial, the bounds, the center of the interval and the error
439
    are returned.
440
    OUTPUT:
441
    A tuple made of 4 Sollya objects:
442
    - a polynomial;
443
    - an range (an interval, not in the sense of number given as an interval);
444
    - the center of the interval;
445
    - the maximum error in the approximation of the input functionSo by the
446
      output polynomial ; this error <= approxPrecSaS.
447
    
448
    """
449
    RRR = lowerBoundSa.parent()
450
    intervalShrinkConstFactorSa = RRR('0.5')
451
    absoluteErrorTypeSo = pobyso_absolute_so_so()
452
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
453
    currentUpperBoundSa = upperBoundSa
454
    currentLowerBoundSa = lowerBoundSa
455
    # What we want here is the polynomial without the variable change, 
456
    # since our actual variable will be x-intervalCenter defined over the 
457
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
458
    (polySo, intervalCenterSo, maxErrorSo) = \
459
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
460
                                                    currentRangeSo, 
461
                                                    absoluteErrorTypeSo)
462
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
463
    while maxErrorSa > approxPrecSa:
464
        #print "++Approximation error:", maxErrorSa
465
        sollya_lib_clear_obj(polySo)
466
        sollya_lib_clear_obj(intervalCenterSo)
467
        sollya_lib_clear_obj(maxErrorSo)
468
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
469
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
470
        #errorRatioSa = approxPrecSa/maxErrorSa
471
        #print "Error ratio: ", errorRatioSa
472
        if shrinkFactorSa > intervalShrinkConstFactorSa:
473
            actualShrinkFactorSa = intervalShrinkConstFactorSa
474
            #print "Fixed"
475
        else:
476
            actualShrinkFactorSa = shrinkFactorSa
477
            #print "Computed",shrinkFactorSa,maxErrorSa
478
            #print shrinkFactorSa, maxErrorSa
479
        #print "Shrink factor", actualShrinkFactorSa
480
        currentUpperBoundSa = currentLowerBoundSa + \
481
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
482
                                   actualShrinkFactorSa
483
        #print "Current upper bound:", currentUpperBoundSa
484
        sollya_lib_clear_obj(currentRangeSo)
485
        if currentUpperBoundSa <= currentLowerBoundSa or \
486
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
487
            sollya_lib_clear_obj(absoluteErrorTypeSo)
488
            print "Can't find an interval."
489
            print "Use either or both a higher polynomial degree or a higher",
490
            print "internal precision."
491
            print "Aborting!"
492
            return (None, None, None, None)
493
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
494
                                                      currentUpperBoundSa)
495
        # print "New interval:",
496
        # pobyso_autoprint(currentRangeSo)
497
        #print "Second Taylor expansion call."
498
        (polySo, intervalCenterSo, maxErrorSo) = \
499
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
500
                                                        currentRangeSo, 
501
                                                        absoluteErrorTypeSo)
502
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
503
        #print "Max errorSo:",
504
        #pobyso_autoprint(maxErrorSo)
505
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
506
        #print "Max errorSa:", maxErrorSa
507
        #print "Sollya prec:",
508
        #pobyso_autoprint(sollya_lib_get_prec(None))
509
    sollya_lib_clear_obj(absoluteErrorTypeSo)
510
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
511
# End slz_compute_polynomial_and_interval
512

    
513
def slz_compute_reduced_polynomial(matrixRow,
514
                                    knownMonomials,
515
                                    var1,
516
                                    var1Bound,
517
                                    var2,
518
                                    var2Bound):
519
    """
520
    Compute a polynomial from a single reduced matrix row.
521
    This function was introduced in order to avoid the computation of the
522
    all the polynomials  from the full matrix (even those built from rows 
523
    that do no verify the Coppersmith condition) as this may involves 
524
    expensive operations over (large) integers.
525
    """
526
    ## Check arguments.
527
    if len(knownMonomials) == 0:
528
        return None
529
    # varNounds can be zero since 0^0 returns 1.
530
    if (var1Bound < 0) or (var2Bound < 0):
531
        return None
532
    ## Initialisations. 
533
    polynomialRing = knownMonomials[0].parent() 
534
    currentPolynomial = polynomialRing(0)
535
    # TODO: use zip instead of indices.
536
    for colIndex in xrange(0, len(knownMonomials)):
537
        currentCoefficient = matrixRow[colIndex]
538
        if currentCoefficient != 0:
539
            #print "Current coefficient:", currentCoefficient
540
            currentMonomial = knownMonomials[colIndex]
541
            #print "Monomial as multivariate polynomial:", \
542
            #currentMonomial, type(currentMonomial)
543
            degreeInVar1 = currentMonomial.degree(var1)
544
            #print "Degree in var1", var1, ":", degreeInVar1
545
            degreeInVar2 = currentMonomial.degree(var2)
546
            #print "Degree in var2", var2, ":", degreeInVar2
547
            if degreeInVar1 > 0:
548
                currentCoefficient = \
549
                    currentCoefficient / (var1Bound^degreeInVar1)
550
                #print "varBound1 in degree:", var1Bound^degreeInVar1
551
                #print "Current coefficient(1)", currentCoefficient
552
            if degreeInVar2 > 0:
553
                currentCoefficient = \
554
                    currentCoefficient / (var2Bound^degreeInVar2)
555
                #print "Current coefficient(2)", currentCoefficient
556
            #print "Current reduced monomial:", (currentCoefficient * \
557
            #                                    currentMonomial)
558
            currentPolynomial += (currentCoefficient * currentMonomial)
559
            #print "Current polynomial:", currentPolynomial
560
        # End if
561
    # End for colIndex.
562
    #print "Type of the current polynomial:", type(currentPolynomial)
563
    return(currentPolynomial)
564
# End slz_compute_reduced_polynomial
565
#
566
def slz_compute_reduced_polynomials(reducedMatrix,
567
                                        knownMonomials,
568
                                        var1,
569
                                        var1Bound,
570
                                        var2,
571
                                        var2Bound):
572
    """
573
    Legacy function, use slz_compute_reduced_polynomials_list
574
    """
575
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
576
                                                knownMonomials,
577
                                                var1,
578
                                                var1Bound,
579
                                                var2,
580
                                                var2Bound)
581
    )
582
def slz_compute_reduced_polynomials_list(reducedMatrix,
583
                                         knownMonomials,
584
                                         var1,
585
                                         var1Bound,
586
                                         var2,
587
                                         var2Bound):
588
    """
589
    From a reduced matrix, holding the coefficients, from a monomials list,
590
    from the bounds of each variable, compute the corresponding polynomials
591
    scaled back by dividing by the "right" powers of the variables bounds.
592
    
593
    The elements in knownMonomials must be of the "right" polynomial type.
594
    They set the polynomial type of the output polynomials list.
595
    @param reducedMatrix:  the reduced matrix as output from LLL;
596
    @param kwnonMonomials: the ordered list of the monomials used to
597
                           build the polynomials;
598
    @param var1:           the first variable (of the "right" type);
599
    @param var1Bound:      the first variable bound;
600
    @param var2:           the second variable (of the "right" type);
601
    @param var2Bound:      the second variable bound.
602
    @return: a list of polynomials obtained with the reduced coefficients
603
             and scaled down with the bounds
604
    """
605
    
606
    # TODO: check input arguments.
607
    reducedPolynomials = []
608
    #print "type var1:", type(var1), " - type var2:", type(var2)
609
    for matrixRow in reducedMatrix.rows():
610
        currentPolynomial = 0
611
        for colIndex in xrange(0, len(knownMonomials)):
612
            currentCoefficient = matrixRow[colIndex]
613
            if currentCoefficient != 0:
614
                #print "Current coefficient:", currentCoefficient
615
                currentMonomial = knownMonomials[colIndex]
616
                parentRing = currentMonomial.parent()
617
                #print "Monomial as multivariate polynomial:", \
618
                #currentMonomial, type(currentMonomial)
619
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
620
                #print "Degree in var", var1, ":", degreeInVar1
621
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
622
                #print "Degree in var", var2, ":", degreeInVar2
623
                if degreeInVar1 > 0:
624
                    currentCoefficient = \
625
                        currentCoefficient / var1Bound^degreeInVar1
626
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
627
                    #print "Current coefficient(1)", currentCoefficient
628
                if degreeInVar2 > 0:
629
                    currentCoefficient = \
630
                        currentCoefficient / var2Bound^degreeInVar2
631
                    #print "Current coefficient(2)", currentCoefficient
632
                #print "Current reduced monomial:", (currentCoefficient * \
633
                #                                    currentMonomial)
634
                currentPolynomial += (currentCoefficient * currentMonomial)
635
                #print "Current polynomial:", currentPolynomial
636
            # End if
637
        # End for colIndex.
638
        #print "Type of the current polynomial:", type(currentPolynomial)
639
        reducedPolynomials.append(currentPolynomial)
640
    return reducedPolynomials 
641
# End slz_compute_reduced_polynomials.
642

    
643
def slz_compute_scaled_function(functionSa,
644
                                lowerBoundSa,
645
                                upperBoundSa,
646
                                floatingPointPrecSa,
647
                                debug=False):
648
    """
649
    From a function, compute the scaled function whose domain
650
    is included in [1, 2) and whose image is also included in [1,2).
651
    Return a tuple: 
652
    [0]: the scaled function
653
    [1]: the scaled domain lower bound
654
    [2]: the scaled domain upper bound
655
    [3]: the scaled image lower bound
656
    [4]: the scaled image upper bound
657
    """
658
    x = functionSa.variables()[0]
659
    # Reassert f as a function (an not a mere expression).
660
    
661
    # Scalling the domain -> [1,2[.
662
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
663
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
664
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
665
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
666
    if debug:
667
        print "domainScalingExpression for argument :", \
668
        invDomainScalingExpressionSa
669
        print "f: ", f
670
    ff = f.subs({x : domainScalingExpressionSa})
671
    #ff = f.subs_expr(x==domainScalingExpressionSa)
672
    domainScalingFunction(x) = invDomainScalingExpressionSa
673
    scaledLowerBoundSa = \
674
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
675
    scaledUpperBoundSa = \
676
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
677
    if debug:
678
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
679
              scaledUpperBoundSa
680
    #
681
    # Scalling the image -> [1,2[.
682
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
683
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
684
    if flbSa <= fubSa: # Increasing
685
        imageBinadeBottomSa = floor(flbSa.log2())
686
    else: # Decreasing
687
        imageBinadeBottomSa = floor(fubSa.log2())
688
    if debug:
689
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
690
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
691
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
692
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
693
    if debug:
694
        print "imageScalingExpression for argument :", \
695
              invImageScalingExpressionSa
696
    iis = invImageScalingExpressionSa.function(x)
697
    fff = iis.subs({x:ff})
698
    if debug:
699
        print "fff:", fff,
700
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
701
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
702
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
703
# End slz_compute_scaled_function
704

    
705
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
706
    # Create a polynomial over the rationals.
707
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
708
    return(polynomialRing(polyOfFloat))
709
# End slz_float_poly_of_float_to_rat_poly_of_rat.
710

    
711
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
712
                                      lowerBoundSa, 
713
                                      upperBoundSa, floatingPointPrecSa, 
714
                                      internalSollyaPrecSa, approxPrecSa):
715
    """
716
    Under the assumption that:
717
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
718
    - lowerBound and upperBound belong to the same binade.
719
    from a:
720
    - function;
721
    - a degree
722
    - a pair of bounds;
723
    - the floating-point precision we work on;
724
    - the internal Sollya precision;
725
    - the requested approximation error
726
    The initial interval is, possibly, splitted into smaller intervals.
727
    It return a list of tuples, each made of:
728
    - a first polynomial (without the changed variable f(x) = p(x-x0));
729
    - a second polynomial (with a changed variable f(x) = q(x))
730
    - the approximation interval;
731
    - the center, x0, of the interval;
732
    - the corresponding approximation error.
733
    TODO: fix endless looping for some parameters sets.
734
    """
735
    resultArray = []
736
    # Set Sollya to the necessary internal precision.
737
    precChangedSa = False
738
    currentSollyaPrecSo = pobyso_get_prec_so()
739
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
740
    if internalSollyaPrecSa > currentSollyaPrecSa:
741
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
742
        precChangedSa = True
743
    #
744
    x = functionSa.variables()[0] # Actual variable name can be anything.
745
    # Scaled function: [1=,2] -> [1,2].
746
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
747
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
748
                slz_compute_scaled_function(functionSa,                       \
749
                                            lowerBoundSa,                     \
750
                                            upperBoundSa,                     \
751
                                            floatingPointPrecSa)
752
    #
753
    print "Approximation precision: ", RR(approxPrecSa)
754
    # Prepare the arguments for the Taylor expansion computation with Sollya.
755
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
756
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
757
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
758
                                                  scaledUpperBoundSa)
759
    # Compute the first Taylor expansion.
760
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
761
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
762
                                        scaledLowerBoundSa, scaledUpperBoundSa,
763
                                        approxPrecSa, internalSollyaPrecSa)
764
    if polySo is None:
765
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
766
        if precChangedSa:
767
            pobyso_set_prec_so_so(currentSollyaPrecSo)
768
            sollya_lib_clear_obj(currentSollyaPrecSo)
769
        sollya_lib_clear_obj(functionSo)
770
        sollya_lib_clear_obj(degreeSo)
771
        sollya_lib_clear_obj(scaledBoundsSo)
772
        return None
773
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
774
                                              upperBoundSa.parent().precision()))
775
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
776
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
777
    print "First approximation error:", errorSa.n(digits=50)
778
    # If the error and interval are OK a the first try, just return.
779
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
780
        # Change variable stuff in Sollya x -> x0-x.
781
        changeVarExpressionSo = sollya_lib_build_function_sub( \
782
                              sollya_lib_build_function_free_variable(), \
783
                              sollya_lib_copy_obj(intervalCenterSo))
784
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
785
        sollya_lib_clear_obj(changeVarExpressionSo)
786
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
787
                            intervalCenterSo, maxErrorSo))
788
        if internalSollyaPrecSa != currentSollyaPrecSa:
789
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
790
        sollya_lib_clear_obj(currentSollyaPrecSo)
791
        sollya_lib_clear_obj(functionSo)
792
        sollya_lib_clear_obj(degreeSo)
793
        sollya_lib_clear_obj(scaledBoundsSo)
794
        #print "Approximation error:", errorSa
795
        return resultArray
796
    # The returned interval upper bound does not reach the requested upper
797
    # upper bound: compute the next upper bound.
798
    # The following ratio is always >= 1
799
    currentErrorRatio = approxPrecSa / errorSa
800
    # Starting point for the next upper bound.
801
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
802
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
803
    # Compute the increment. 
804
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
805
        currentScaledUpperBoundSa += \
806
                        currentErrorRatio * boundsWidthSa * 2
807
    else:  # [1, 1.5]
808
        currentScaledUpperBoundSa += \
809
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
810
    # Take into account the original interval upper bound.                     
811
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
812
        currentScaledUpperBoundSa = scaledUpperBoundSa
813
    # Compute the other expansions.
814
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
815
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
816
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
817
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
818
                                            currentScaledLowerBoundSa, 
819
                                            currentScaledUpperBoundSa, 
820
                                            approxPrecSa, 
821
                                            internalSollyaPrecSa)
822
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
823
        if  errorSa < approxPrecSa:
824
            # Change variable stuff
825
            #print "Approximation error:", errorSa
826
            changeVarExpressionSo = sollya_lib_build_function_sub(
827
                                    sollya_lib_build_function_free_variable(), 
828
                                    sollya_lib_copy_obj(intervalCenterSo))
829
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
830
            sollya_lib_clear_obj(changeVarExpressionSo)
831
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
832
                                intervalCenterSo, maxErrorSo))
833
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
834
        # Compute the next upper bound.
835
        # The following ratio is always >= 1
836
        currentErrorRatio = approxPrecSa / errorSa
837
        # Starting point for the next upper bound.
838
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
839
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
840
        # Compute the increment. 
841
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
842
            currentScaledUpperBoundSa += \
843
                            currentErrorRatio * boundsWidthSa * 2
844
        else:  # [1, 1.5]
845
            currentScaledUpperBoundSa += \
846
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
847
        #print "currentErrorRatio:", currentErrorRatio
848
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
849
        # Test for insufficient precision.
850
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
851
            print "Can't shrink the interval anymore!"
852
            print "You should consider increasing the Sollya internal precision"
853
            print "or the polynomial degree."
854
            print "Giving up!"
855
            if internalSollyaPrecSa != currentSollyaPrecSa:
856
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
857
            sollya_lib_clear_obj(currentSollyaPrecSo)
858
            sollya_lib_clear_obj(functionSo)
859
            sollya_lib_clear_obj(degreeSo)
860
            sollya_lib_clear_obj(scaledBoundsSo)
861
            return None
862
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
863
            currentScaledUpperBoundSa = scaledUpperBoundSa
864
    if internalSollyaPrecSa > currentSollyaPrecSa:
865
        pobyso_set_prec_so_so(currentSollyaPrecSo)
866
    sollya_lib_clear_obj(currentSollyaPrecSo)
867
    sollya_lib_clear_obj(functionSo)
868
    sollya_lib_clear_obj(degreeSo)
869
    sollya_lib_clear_obj(scaledBoundsSo)
870
    return(resultArray)
871
# End slz_get_intervals_and_polynomials
872

    
873

    
874
def slz_interval_scaling_expression(boundsInterval, expVar):
875
    """
876
    Compute the scaling expression to map an interval that spans at most
877
    a single binade to [1, 2) and the inverse expression as well.
878
    Not very sure that the transformation makes sense for negative numbers.
879
    """
880
    # The scaling offset is only used for negative numbers.
881
    # When the absolute value of the lower bound is < 0.
882
    if abs(boundsInterval.endpoints()[0]) < 1:
883
        if boundsInterval.endpoints()[0] >= 0:
884
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
885
            invScalingCoeff = 1/scalingCoeff
886
            return((scalingCoeff * expVar, 
887
                    invScalingCoeff * expVar))
888
        else:
889
            scalingCoeff = \
890
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
891
            scalingOffset = -3 * scalingCoeff
892
            return((scalingCoeff * expVar + scalingOffset,
893
                    1/scalingCoeff * expVar + 3))
894
    else: 
895
        if boundsInterval.endpoints()[0] >= 0:
896
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
897
            scalingOffset = 0
898
            return((scalingCoeff * expVar, 
899
                    1/scalingCoeff * expVar))
900
        else:
901
            scalingCoeff = \
902
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
903
            scalingOffset =  -3 * scalingCoeff
904
            #scalingOffset = 0
905
            return((scalingCoeff * expVar + scalingOffset,
906
                    1/scalingCoeff * expVar + 3))
907
# End slz_interval_scaling_expression
908
   
909
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
910
    """
911
    Compute the Sage version of the Taylor polynomial and it's
912
    companion data (interval, center...)
913
    The input parameter is a five elements tuple:
914
    - [0]: the polyomial (without variable change), as polynomial over a
915
           real ring;
916
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
917
           over a real ring;
918
    - [2]: the interval (as Sollya range);
919
    - [3]: the interval center;
920
    - [4]: the approximation error. 
921
    
922
    The function return a 5 elements tuple: formed with all the 
923
    input elements converted into their Sollya counterpart.
924
    """
925
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
926
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
927
    intervalSa = \
928
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
929
    centerSa = \
930
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
931
    errorSa = \
932
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
933
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
934
    # End slz_interval_and_polynomial_to_sage
935

    
936
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
937
                                                precision,
938
                                                targetHardnessToRound,
939
                                                variable1,
940
                                                variable2):
941
    """
942
    Creates a new multivariate polynomial with integer coefficients for use
943
     with the Coppersmith method.
944
    A the same time it computes :
945
    - 2^K (N);
946
    - 2^k (bound on the second variable)
947
    - lcm
948

    
949
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
950
                         variables.
951
    :param precision: the precision of the floating-point coefficients.
952
    :param targetHardnessToRound: the hardness to round we want to check.
953
    :param variable1: the first variable of the polynomial (an expression).
954
    :param variable2: the second variable of the polynomial (an expression).
955
    
956
    :returns: a 4 elements tuple:
957
                - the polynomial;
958
                - the modulus (N);
959
                - the t bound;
960
                - the lcm used to compute the integral coefficients and the 
961
                  module.
962
    """
963
    # Create a new integer polynomial ring.
964
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
965
    # Coefficients are issued in the increasing power order.
966
    ratPolyCoefficients = ratPolyOfInt.coefficients()
967
    # Print the reversed list for debugging.
968
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
969
    # Build the list of number we compute the lcm of.
970
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
971
    coefficientDenominators.append(2^precision)
972
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
973
    leastCommonMultiple = lcm(coefficientDenominators)
974
    # Compute the expression corresponding to the new polynomial
975
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
976
    #print coefficientNumerators
977
    polynomialExpression = 0
978
    power = 0
979
    # Iterate over two lists at the same time, stop when the shorter is
980
    # exhausted.
981
    for numerator, denominator in \
982
                        zip(coefficientNumerators, coefficientDenominators):
983
        multiplicator = leastCommonMultiple / denominator 
984
        newCoefficient = numerator * multiplicator
985
        polynomialExpression += newCoefficient * variable1^power
986
        power +=1
987
    polynomialExpression += - variable2
988
    return (IP(polynomialExpression),
989
            leastCommonMultiple / 2^precision, # 2^K or N.
990
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
991
            leastCommonMultiple) # If we want to make test computations.
992
        
993
# End slz_ratPoly_of_int_to_poly_for_coppersmith
994

    
995
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
996
                                          precision):
997
    """
998
    Makes a variable substitution into the input polynomial so that the output
999
    polynomial can take integer arguments.
1000
    All variables of the input polynomial "have precision p". That is to say
1001
    that they are rationals with denominator == 2^(precision - 1): 
1002
    x = y/2^(precision - 1).
1003
    We "incorporate" these denominators into the coefficients with, 
1004
    respectively, the "right" power.
1005
    """
1006
    polynomialField = ratPolyOfRat.parent()
1007
    polynomialVariable = ratPolyOfRat.variables()[0]
1008
    #print "The polynomial field is:", polynomialField
1009
    return \
1010
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1011
                                   polynomialVariable/2^(precision-1)}))
1012
    
1013
    # Return a tuple:
1014
    # - the bivariate integer polynomial in (i,j);
1015
    # - 2^K
1016
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1017

    
1018

    
1019
print "\t...sageSLZ loaded"