Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (69,24 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_compute_binade(number):
14
    """"
15
    For a given number, compute the "binade" that is integer m such that
16
    2^m <= number < 2^(m+1). If number == 0 return None.
17
    """
18
    # Checking the parameter.
19
    # The exception construction is used to detect if number is a RealNumber
20
    # since not all numbers have
21
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
22
    try:
23
        classTree = [number.__class__] + number.mro()
24
        # If the number is not a RealNumber (or offspring thereof) try
25
        # to transform it.
26
        if not sage.rings.real_mpfr.RealNumber in classTree:
27
            numberAsRR = RR(number)
28
        else:
29
            numberAsRR = number
30
    except AttributeError:
31
        return None
32
    # Zero special case.
33
    if numberAsRR == 0:
34
        return RR(-infinity)
35
    else:
36
        realField           = numberAsRR.parent()
37
        numberLog2          = numberAsRR.abs().log2()
38
        floorNumberLog2     = floor(numberLog2)
39
        ## Do not get caught by rounding of log2() both ways.
40
        ## When numberLog2 is an integer, compare numberAsRR
41
        #  with 2^numberLog2.
42
        if floorNumberLog2 == numberLog2:
43
            if numberAsRR.abs() < realField(2^floorNumberLog2):
44
                return floorNumberLog2 - 1
45
            else:
46
                return floorNumberLog2
47
        else:
48
            return floorNumberLog2
49
# End slz_compute_binade
50

    
51
#
52
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
53
    """
54
    For given "real number", compute the bounds of the binade it belongs to.
55
    
56
    NOTE::
57
        When number >= 2^(emax+1), we return the "fake" binade 
58
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
59
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
60
        this case from that of "really" invalid arguments.
61
        
62
    """
63
    # Check the parameters.
64
    # RealNumbers or RealNumber offspring only.
65
    # The exception construction is necessary since not all objects have
66
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
67
    try:
68
        classTree = [number.__class__] + number.mro()
69
        if not sage.rings.real_mpfr.RealNumber in classTree:
70
            return None
71
    except AttributeError:
72
        return None
73
    # Non zero negative integers only for emin.
74
    if emin >= 0 or int(emin) != emin:
75
        return None
76
    # Non zero positive integers only for emax.
77
    if emax <= 0 or int(emax) != emax:
78
        return None
79
    precision = number.precision()
80
    RF  = RealField(precision)
81
    if number == 0:
82
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
83
    # A more precise RealField is needed to avoid unwanted rounding effects
84
    # when computing number.log2().
85
    RRF = RealField(max(2048, 2 * precision))
86
    # number = 0 special case, the binade bounds are 
87
    # [0, 2^emin - 2^(emin-precision)]
88
    # Begin general case
89
    l2 = RRF(number).abs().log2()
90
    # Another special one: beyond largest representable -> "Fake" binade.
91
    if l2 >= emax + 1:
92
        if number > 0:
93
            return (RF(2^(emax+1)), RF(+infinity) )
94
        else:
95
            return (RF(-infinity), -RF(2^(emax+1)))
96
    # Regular case cont'd.
97
    offset = int(l2)
98
    # number.abs() >= 1.
99
    if l2 >= 0:
100
        if number >= 0:
101
            lb = RF(2^offset)
102
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
103
        else: #number < 0
104
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
105
            ub = -RF(2^offset)
106
    else: # log2 < 0, number.abs() < 1.
107
        if l2 < emin: # Denormal
108
           # print "Denormal:", l2
109
            if number >= 0:
110
                lb = RF(0)
111
                ub = RF(2^(emin)) - RF(2^(emin-precision))
112
            else: # number <= 0
113
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
114
                ub = RF(0)
115
        elif l2 > emin: # Normal number other than +/-2^emin.
116
            if number >= 0:
117
                if int(l2) == l2:
118
                    lb = RF(2^(offset))
119
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
120
                else:
121
                    lb = RF(2^(offset-1))
122
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
123
            else: # number < 0
124
                if int(l2) == l2: # Binade limit.
125
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
126
                    ub = -RF(2^(offset))
127
                else:
128
                    lb = -RF(2^(offset) - 2^(-precision+offset))
129
                    ub = -RF(2^(offset-1))
130
        else: # l2== emin, number == +/-2^emin
131
            if number >= 0:
132
                lb = RF(2^(offset))
133
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
134
            else: # number < 0
135
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
136
                ub = -RF(2^(offset))
137
    return (lb, ub)
138
# End slz_compute_binade_bounds
139
#
140
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
141
                                                 alpha,
142
                                                 N,
143
                                                 iBound,
144
                                                 tBound):
145
    """
146
    For a given set of arguments (see below), compute a list
147
    of "reduced polynomials" that could be used to compute roots
148
    of the inputPolynomial.
149
    INPUT:
150
    
151
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
152
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
153
    - "N" -- the modulus;
154
    - "iBound" -- the bound on the first variable;
155
    - "tBound" -- the bound on the second variable.
156
    
157
    OUTPUT:
158
    
159
    A list of bivariate integer polynomial obtained using the Coppersmith
160
    algorithm. The polynomials correspond to the rows of the LLL-reduce
161
    reduced base that comply with the Coppersmith condition.
162
    """
163
    # Arguments check.
164
    if iBound == 0 or tBound == 0:
165
        return None
166
    # End arguments check.
167
    nAtAlpha = N^alpha
168
    ## Building polynomials for matrix.
169
    polyRing   = inputPolynomial.parent()
170
    # Whatever the 2 variables are actually called, we call them
171
    # 'i' and 't' in all the variable names.
172
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
173
    #print polyVars[0], type(polyVars[0])
174
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
175
                                              tVariable:tVariable * tBound})
176
    polynomialsList = \
177
        spo_polynomial_to_polynomials_list_8(initialPolynomial,
178
                                             alpha,
179
                                             N,
180
                                             iBound,
181
                                             tBound,
182
                                             0)
183
    #print "Polynomials list:", polynomialsList
184
    ## Building the proto matrix.
185
    knownMonomials = []
186
    protoMatrix    = []
187
    for poly in polynomialsList:
188
        spo_add_polynomial_coeffs_to_matrix_row(poly,
189
                                                knownMonomials,
190
                                                protoMatrix,
191
                                                0)
192
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
193
    #print matrixToReduce
194
    ## Reduction and checking.
195
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
196
    #  error message issued when previous code was used.
197
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
198
    reducedMatrix = matrixToReduce.LLL(fp=None)
199
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
200
    if not isLLLReduced:
201
        return None
202
    monomialsCount     = len(knownMonomials)
203
    monomialsCountSqrt = sqrt(monomialsCount)
204
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
205
    #print reducedMatrix
206
    ## Check the Coppersmith condition for each row and build the reduced 
207
    #  polynomials.
208
    ccReducedPolynomialsList = []
209
    for row in reducedMatrix.rows():
210
        l2Norm = row.norm(2)
211
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
212
            #print (l2Norm * monomialsCountSqrt).n()
213
            #print l2Norm.n()
214
            ccReducedPolynomial = \
215
                slz_compute_reduced_polynomial(row,
216
                                               knownMonomials,
217
                                               iVariable,
218
                                               iBound,
219
                                               tVariable,
220
                                               tBound)
221
            if not ccReducedPolynomial is None:
222
                ccReducedPolynomialsList.append(ccReducedPolynomial)
223
        else:
224
            #print l2Norm.n() , ">", nAtAlpha
225
            pass
226
    if len(ccReducedPolynomialsList) < 2:
227
        print "Less than 2 Coppersmith condition compliant vectors."
228
        return ()
229
    #print ccReducedPolynomialsList
230
    return ccReducedPolynomialsList
231
# End slz_compute_coppersmith_reduced_polynomials
232

    
233
def slz_compute_coppersmith_reduced_polynomials_with_lattice_volume(inputPolynomial,
234
                                                                    alpha,
235
                                                                    N,
236
                                                                    iBound,
237
                                                                    tBound):
238
    """
239
    For a given set of arguments (see below), compute a list
240
    of "reduced polynomials" that could be used to compute roots
241
    of the inputPolynomial.
242
    Print the volume of the initial basis as well.
243
    INPUT:
244
    
245
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
246
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
247
    - "N" -- the modulus;
248
    - "iBound" -- the bound on the first variable;
249
    - "tBound" -- the bound on the second variable.
250
    
251
    OUTPUT:
252
    
253
    A list of bivariate integer polynomial obtained using the Coppersmith
254
    algorithm. The polynomials correspond to the rows of the LLL-reduce
255
    reduced base that comply with the Coppersmith condition.
256
    """
257
    # Arguments check.
258
    if iBound == 0 or tBound == 0:
259
        return None
260
    # End arguments check.
261
    nAtAlpha = N^alpha
262
    ## Building polynomials for matrix.
263
    polyRing   = inputPolynomial.parent()
264
    # Whatever the 2 variables are actually called, we call them
265
    # 'i' and 't' in all the variable names.
266
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
267
    #print polyVars[0], type(polyVars[0])
268
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
269
                                              tVariable:tVariable * tBound})
270
##    polynomialsList = \
271
##        spo_polynomial_to_polynomials_list_8(initialPolynomial,
272
##        spo_polynomial_to_polynomials_list_5(initialPolynomial,
273
    polynomialsList = \
274
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
275
                                             alpha,
276
                                             N,
277
                                             iBound,
278
                                             tBound,
279
                                             0)
280
    #print "Polynomials list:", polynomialsList
281
    ## Building the proto matrix.
282
    knownMonomials = []
283
    protoMatrix    = []
284
    for poly in polynomialsList:
285
        spo_add_polynomial_coeffs_to_matrix_row(poly,
286
                                                knownMonomials,
287
                                                protoMatrix,
288
                                                0)
289
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
290
    matrixToReduceTranspose = matrixToReduce.transpose()
291
    squareMatrix = matrixToReduce * matrixToReduceTranspose
292
    squareMatDet = det(squareMatrix)
293
    latticeVolume = sqrt(squareMatDet)
294
    print "Lattice volume:", latticeVolume.n()
295
    print "Lattice volume / N:", (latticeVolume/N).n()
296
    #print matrixToReduce
297
    ## Reduction and checking.
298
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
299
    #  error message issued when previous code was used.
300
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
301
    reductionTimeStart = cputime() 
302
    reducedMatrix = matrixToReduce.LLL(fp=None)
303
    reductionTime = cputime(reductionTimeStart)
304
    print "Reduction time:", reductionTime
305
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
306
    if not isLLLReduced:
307
        return None
308
    monomialsCount     = len(knownMonomials)
309
    monomialsCountSqrt = sqrt(monomialsCount)
310
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
311
    #print reducedMatrix
312
    ## Check the Coppersmith condition for each row and build the reduced 
313
    #  polynomials.
314
    ccReducedPolynomialsList = []
315
    for row in reducedMatrix.rows():
316
        l2Norm = row.norm(2)
317
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
318
            #print (l2Norm * monomialsCountSqrt).n()
319
            #print l2Norm.n()
320
            ccReducedPolynomial = \
321
                slz_compute_reduced_polynomial(row,
322
                                               knownMonomials,
323
                                               iVariable,
324
                                               iBound,
325
                                               tVariable,
326
                                               tBound)
327
            if not ccReducedPolynomial is None:
328
                ccReducedPolynomialsList.append(ccReducedPolynomial)
329
        else:
330
            #print l2Norm.n() , ">", nAtAlpha
331
            pass
332
    if len(ccReducedPolynomialsList) < 2:
333
        print "Less than 2 Coppersmith condition compliant vectors."
334
        return ()
335
    #print ccReducedPolynomialsList
336
    return ccReducedPolynomialsList
337
# End slz_compute_coppersmith_reduced_polynomials_with_lattice volume
338

    
339
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
340
                                                 alpha,
341
                                                 N,
342
                                                 iBound,
343
                                                 tBound):
344
    """
345
    For a given set of arguments (see below), compute the polynomial modular 
346
    roots, if any.
347
    
348
    """
349
    # Arguments check.
350
    if iBound == 0 or tBound == 0:
351
        return set()
352
    # End arguments check.
353
    nAtAlpha = N^alpha
354
    ## Building polynomials for matrix.
355
    polyRing   = inputPolynomial.parent()
356
    # Whatever the 2 variables are actually called, we call them
357
    # 'i' and 't' in all the variable names.
358
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
359
    ccReducedPolynomialsList = \
360
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
361
                                                     alpha,
362
                                                     N,
363
                                                     iBound,
364
                                                     tBound)
365
    if len(ccReducedPolynomialsList) == 0:
366
        return set()   
367
    ## Create the valid (poly1 and poly2 are algebraically independent) 
368
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
369
    # Try to mix and match all the polynomial pairs built from the 
370
    # ccReducedPolynomialsList to obtain non zero resultants.
371
    resultantsInITuplesList = []
372
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
373
        for polyInnerIndex in xrange(polyOuterIndex+1, 
374
                                     len(ccReducedPolynomialsList)):
375
            # Compute the resultant in resultants in the
376
            # first variable (is it the optimal choice?).
377
            resultantInI = \
378
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
379
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
380
            #print "Resultant", resultantInI
381
            # Test algebraic independence.
382
            if not resultantInI.is_zero():
383
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
384
                                                 ccReducedPolynomialsList[polyInnerIndex],
385
                                                 resultantInI))
386
    # If no non zero resultant was found: we can't get no algebraically 
387
    # independent polynomials pair. Give up!
388
    if len(resultantsInITuplesList) == 0:
389
        return set()
390
    #print resultantsInITuplesList
391
    # Compute the roots.
392
    Zi = ZZ[str(iVariable)]
393
    Zt = ZZ[str(tVariable)]
394
    polynomialRootsSet = set()
395
    # First, solve in the second variable since resultants are in the first
396
    # variable.
397
    for resultantInITuple in resultantsInITuplesList:
398
        tRootsList = Zt(resultantInITuple[2]).roots()
399
        # For each tRoot, compute the corresponding iRoots and check 
400
        # them in the input polynomial.
401
        for tRoot in tRootsList:
402
            #print "tRoot:", tRoot
403
            # Roots returned by root() are (value, multiplicity) tuples.
404
            iRootsList = \
405
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
406
            print iRootsList
407
            # The iRootsList can be empty, hence the test.
408
            if len(iRootsList) != 0:
409
                for iRoot in iRootsList:
410
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
411
                    # polyEvalModN must be an integer.
412
                    if polyEvalModN == int(polyEvalModN):
413
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
414
    return polynomialRootsSet
415
# End slz_compute_integer_polynomial_modular_roots.
416
#
417
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
418
                                                 alpha,
419
                                                 N,
420
                                                 iBound,
421
                                                 tBound):
422
    """
423
    For a given set of arguments (see below), compute the polynomial modular 
424
    roots, if any.
425
    This version differs in the way resultants are computed.   
426
    """
427
    # Arguments check.
428
    if iBound == 0 or tBound == 0:
429
        return set()
430
    # End arguments check.
431
    nAtAlpha = N^alpha
432
    ## Building polynomials for matrix.
433
    polyRing   = inputPolynomial.parent()
434
    # Whatever the 2 variables are actually called, we call them
435
    # 'i' and 't' in all the variable names.
436
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
437
    #print polyVars[0], type(polyVars[0])
438
    ccReducedPolynomialsList = \
439
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
440
                                                     alpha,
441
                                                     N,
442
                                                     iBound,
443
                                                     tBound)
444
    if len(ccReducedPolynomialsList) == 0:
445
        return set()   
446
    ## Create the valid (poly1 and poly2 are algebraically independent) 
447
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
448
    # Try to mix and match all the polynomial pairs built from the 
449
    # ccReducedPolynomialsList to obtain non zero resultants.
450
    resultantsInTTuplesList = []
451
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
452
        for polyInnerIndex in xrange(polyOuterIndex+1, 
453
                                     len(ccReducedPolynomialsList)):
454
            # Compute the resultant in resultants in the
455
            # first variable (is it the optimal choice?).
456
            resultantInT = \
457
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
458
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
459
            #print "Resultant", resultantInT
460
            # Test algebraic independence.
461
            if not resultantInT.is_zero():
462
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
463
                                                 ccReducedPolynomialsList[polyInnerIndex],
464
                                                 resultantInT))
465
    # If no non zero resultant was found: we can't get no algebraically 
466
    # independent polynomials pair. Give up!
467
    if len(resultantsInTTuplesList) == 0:
468
        return set()
469
    #print resultantsInITuplesList
470
    # Compute the roots.
471
    Zi = ZZ[str(iVariable)]
472
    Zt = ZZ[str(tVariable)]
473
    polynomialRootsSet = set()
474
    # First, solve in the second variable since resultants are in the first
475
    # variable.
476
    for resultantInTTuple in resultantsInTTuplesList:
477
        iRootsList = Zi(resultantInTTuple[2]).roots()
478
        # For each iRoot, compute the corresponding tRoots and check 
479
        # them in the input polynomial.
480
        for iRoot in iRootsList:
481
            #print "iRoot:", iRoot
482
            # Roots returned by root() are (value, multiplicity) tuples.
483
            tRootsList = \
484
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
485
            print tRootsList
486
            # The tRootsList can be empty, hence the test.
487
            if len(tRootsList) != 0:
488
                for tRoot in tRootsList:
489
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
490
                    # polyEvalModN must be an integer.
491
                    if polyEvalModN == int(polyEvalModN):
492
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
493
    return polynomialRootsSet
494
# End slz_compute_integer_polynomial_modular_roots_2.
495
#
496
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa, 
497
                                        upperBoundSa, approxPrecSa, 
498
                                        sollyaPrecSa=None):
499
    """
500
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
501
    a polynomial that approximates the function on a an interval starting
502
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
503
    approximates with the expected precision.
504
    The interval upper bound is lowered until the expected approximation 
505
    precision is reached.
506
    The polynomial, the bounds, the center of the interval and the error
507
    are returned.
508
    OUTPUT:
509
    A tuple made of 4 Sollya objects:
510
    - a polynomial;
511
    - an range (an interval, not in the sense of number given as an interval);
512
    - the center of the interval;
513
    - the maximum error in the approximation of the input functionSo by the
514
      output polynomial ; this error <= approxPrecSaS.
515
    
516
    """
517
    ## Superficial argument check.
518
    if lowerBoundSa > upperBoundSa:
519
        return None
520
    RRR = lowerBoundSa.parent()
521
    intervalShrinkConstFactorSa = RRR('0.9')
522
    absoluteErrorTypeSo = pobyso_absolute_so_so()
523
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
524
    currentUpperBoundSa = upperBoundSa
525
    currentLowerBoundSa = lowerBoundSa
526
    # What we want here is the polynomial without the variable change, 
527
    # since our actual variable will be x-intervalCenter defined over the 
528
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
529
    (polySo, intervalCenterSo, maxErrorSo) = \
530
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
531
                                                    currentRangeSo, 
532
                                                    absoluteErrorTypeSo)
533
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
534
    while maxErrorSa > approxPrecSa:
535
        print "++Approximation error:", maxErrorSa.n()
536
        sollya_lib_clear_obj(polySo)
537
        sollya_lib_clear_obj(intervalCenterSo)
538
        sollya_lib_clear_obj(maxErrorSo)
539
        # Very empirical shrinking factor.
540
        shrinkFactorSa = 1 /  (maxErrorSa/approxPrecSa).log2().abs()
541
        print "Shrink factor:", \
542
              shrinkFactorSa.n(), \
543
              intervalShrinkConstFactorSa
544
        print
545
        #errorRatioSa = approxPrecSa/maxErrorSa
546
        #print "Error ratio: ", errorRatioSa
547
        # Make sure interval shrinks.
548
        if shrinkFactorSa > intervalShrinkConstFactorSa:
549
            actualShrinkFactorSa = intervalShrinkConstFactorSa
550
            #print "Fixed"
551
        else:
552
            actualShrinkFactorSa = shrinkFactorSa
553
            #print "Computed",shrinkFactorSa,maxErrorSa
554
            #print shrinkFactorSa, maxErrorSa
555
        #print "Shrink factor", actualShrinkFactorSa
556
        currentUpperBoundSa = currentLowerBoundSa + \
557
                                (currentUpperBoundSa - currentLowerBoundSa) * \
558
                                actualShrinkFactorSa
559
        #print "Current upper bound:", currentUpperBoundSa
560
        sollya_lib_clear_obj(currentRangeSo)
561
        # Check what is left with the bounds.
562
        if currentUpperBoundSa <= currentLowerBoundSa or \
563
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
564
            sollya_lib_clear_obj(absoluteErrorTypeSo)
565
            print "Can't find an interval."
566
            print "Use either or both a higher polynomial degree or a higher",
567
            print "internal precision."
568
            print "Aborting!"
569
            return (None, None, None, None)
570
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
571
                                                      currentUpperBoundSa)
572
        # print "New interval:",
573
        # pobyso_autoprint(currentRangeSo)
574
        #print "Second Taylor expansion call."
575
        (polySo, intervalCenterSo, maxErrorSo) = \
576
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
577
                                                        currentRangeSo, 
578
                                                        absoluteErrorTypeSo)
579
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
580
        #print "Max errorSo:",
581
        #pobyso_autoprint(maxErrorSo)
582
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
583
        #print "Max errorSa:", maxErrorSa
584
        #print "Sollya prec:",
585
        #pobyso_autoprint(sollya_lib_get_prec(None))
586
    sollya_lib_clear_obj(absoluteErrorTypeSo)
587
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
588
# End slz_compute_polynomial_and_interval
589

    
590
def slz_compute_reduced_polynomial(matrixRow,
591
                                    knownMonomials,
592
                                    var1,
593
                                    var1Bound,
594
                                    var2,
595
                                    var2Bound):
596
    """
597
    Compute a polynomial from a single reduced matrix row.
598
    This function was introduced in order to avoid the computation of the
599
    all the polynomials  from the full matrix (even those built from rows 
600
    that do no verify the Coppersmith condition) as this may involves 
601
    expensive operations over (large) integers.
602
    """
603
    ## Check arguments.
604
    if len(knownMonomials) == 0:
605
        return None
606
    # varNounds can be zero since 0^0 returns 1.
607
    if (var1Bound < 0) or (var2Bound < 0):
608
        return None
609
    ## Initialisations. 
610
    polynomialRing = knownMonomials[0].parent() 
611
    currentPolynomial = polynomialRing(0)
612
    # TODO: use zip instead of indices.
613
    for colIndex in xrange(0, len(knownMonomials)):
614
        currentCoefficient = matrixRow[colIndex]
615
        if currentCoefficient != 0:
616
            #print "Current coefficient:", currentCoefficient
617
            currentMonomial = knownMonomials[colIndex]
618
            #print "Monomial as multivariate polynomial:", \
619
            #currentMonomial, type(currentMonomial)
620
            degreeInVar1 = currentMonomial.degree(var1)
621
            #print "Degree in var1", var1, ":", degreeInVar1
622
            degreeInVar2 = currentMonomial.degree(var2)
623
            #print "Degree in var2", var2, ":", degreeInVar2
624
            if degreeInVar1 > 0:
625
                currentCoefficient = \
626
                    currentCoefficient / (var1Bound^degreeInVar1)
627
                #print "varBound1 in degree:", var1Bound^degreeInVar1
628
                #print "Current coefficient(1)", currentCoefficient
629
            if degreeInVar2 > 0:
630
                currentCoefficient = \
631
                    currentCoefficient / (var2Bound^degreeInVar2)
632
                #print "Current coefficient(2)", currentCoefficient
633
            #print "Current reduced monomial:", (currentCoefficient * \
634
            #                                    currentMonomial)
635
            currentPolynomial += (currentCoefficient * currentMonomial)
636
            #print "Current polynomial:", currentPolynomial
637
        # End if
638
    # End for colIndex.
639
    #print "Type of the current polynomial:", type(currentPolynomial)
640
    return(currentPolynomial)
641
# End slz_compute_reduced_polynomial
642
#
643
def slz_compute_reduced_polynomials(reducedMatrix,
644
                                        knownMonomials,
645
                                        var1,
646
                                        var1Bound,
647
                                        var2,
648
                                        var2Bound):
649
    """
650
    Legacy function, use slz_compute_reduced_polynomials_list
651
    """
652
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
653
                                                knownMonomials,
654
                                                var1,
655
                                                var1Bound,
656
                                                var2,
657
                                                var2Bound)
658
    )
659
#
660
def slz_compute_reduced_polynomials_list(reducedMatrix,
661
                                         knownMonomials,
662
                                         var1,
663
                                         var1Bound,
664
                                         var2,
665
                                         var2Bound):
666
    """
667
    From a reduced matrix, holding the coefficients, from a monomials list,
668
    from the bounds of each variable, compute the corresponding polynomials
669
    scaled back by dividing by the "right" powers of the variables bounds.
670
    
671
    The elements in knownMonomials must be of the "right" polynomial type.
672
    They set the polynomial type of the output polynomials in list.
673
    @param reducedMatrix:  the reduced matrix as output from LLL;
674
    @param kwnonMonomials: the ordered list of the monomials used to
675
                           build the polynomials;
676
    @param var1:           the first variable (of the "right" type);
677
    @param var1Bound:      the first variable bound;
678
    @param var2:           the second variable (of the "right" type);
679
    @param var2Bound:      the second variable bound.
680
    @return: a list of polynomials obtained with the reduced coefficients
681
             and scaled down with the bounds
682
    """
683
    
684
    # TODO: check input arguments.
685
    reducedPolynomials = []
686
    #print "type var1:", type(var1), " - type var2:", type(var2)
687
    for matrixRow in reducedMatrix.rows():
688
        currentPolynomial = 0
689
        for colIndex in xrange(0, len(knownMonomials)):
690
            currentCoefficient = matrixRow[colIndex]
691
            if currentCoefficient != 0:
692
                #print "Current coefficient:", currentCoefficient
693
                currentMonomial = knownMonomials[colIndex]
694
                parentRing = currentMonomial.parent()
695
                #print "Monomial as multivariate polynomial:", \
696
                #currentMonomial, type(currentMonomial)
697
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
698
                #print "Degree in var", var1, ":", degreeInVar1
699
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
700
                #print "Degree in var", var2, ":", degreeInVar2
701
                if degreeInVar1 > 0:
702
                    currentCoefficient /= var1Bound^degreeInVar1
703
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
704
                    #print "Current coefficient(1)", currentCoefficient
705
                if degreeInVar2 > 0:
706
                    currentCoefficient /= var2Bound^degreeInVar2
707
                    #print "Current coefficient(2)", currentCoefficient
708
                #print "Current reduced monomial:", (currentCoefficient * \
709
                #                                    currentMonomial)
710
                currentPolynomial += (currentCoefficient * currentMonomial)
711
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
712
                    #print "!!!! constant term !!!!"
713
                #print "Current polynomial:", currentPolynomial
714
            # End if
715
        # End for colIndex.
716
        #print "Type of the current polynomial:", type(currentPolynomial)
717
        reducedPolynomials.append(currentPolynomial)
718
    return reducedPolynomials 
719
# End slz_compute_reduced_polynomials_list.
720

    
721
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
722
                                                   knownMonomials,
723
                                                   var1,
724
                                                   var1Bound,
725
                                                   var2,
726
                                                   var2Bound):
727
    """
728
    From a list of rows, holding the coefficients, from a monomials list,
729
    from the bounds of each variable, compute the corresponding polynomials
730
    scaled back by dividing by the "right" powers of the variables bounds.
731
    
732
    The elements in knownMonomials must be of the "right" polynomial type.
733
    They set the polynomial type of the output polynomials in list.
734
    @param rowsList:       the reduced matrix as output from LLL;
735
    @param kwnonMonomials: the ordered list of the monomials used to
736
                           build the polynomials;
737
    @param var1:           the first variable (of the "right" type);
738
    @param var1Bound:      the first variable bound;
739
    @param var2:           the second variable (of the "right" type);
740
    @param var2Bound:      the second variable bound.
741
    @return: a list of polynomials obtained with the reduced coefficients
742
             and scaled down with the bounds
743
    """
744
    
745
    # TODO: check input arguments.
746
    reducedPolynomials = []
747
    #print "type var1:", type(var1), " - type var2:", type(var2)
748
    for matrixRow in rowsList:
749
        currentPolynomial = 0
750
        for colIndex in xrange(0, len(knownMonomials)):
751
            currentCoefficient = matrixRow[colIndex]
752
            if currentCoefficient != 0:
753
                #print "Current coefficient:", currentCoefficient
754
                currentMonomial = knownMonomials[colIndex]
755
                parentRing = currentMonomial.parent()
756
                #print "Monomial as multivariate polynomial:", \
757
                #currentMonomial, type(currentMonomial)
758
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
759
                #print "Degree in var", var1, ":", degreeInVar1
760
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
761
                #print "Degree in var", var2, ":", degreeInVar2
762
                if degreeInVar1 > 0:
763
                    currentCoefficient /= var1Bound^degreeInVar1
764
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
765
                    #print "Current coefficient(1)", currentCoefficient
766
                if degreeInVar2 > 0:
767
                    currentCoefficient /= var2Bound^degreeInVar2
768
                    #print "Current coefficient(2)", currentCoefficient
769
                #print "Current reduced monomial:", (currentCoefficient * \
770
                #                                    currentMonomial)
771
                currentPolynomial += (currentCoefficient * currentMonomial)
772
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
773
                    #print "!!!! constant term !!!!"
774
                #print "Current polynomial:", currentPolynomial
775
            # End if
776
        # End for colIndex.
777
        #print "Type of the current polynomial:", type(currentPolynomial)
778
        reducedPolynomials.append(currentPolynomial)
779
    return reducedPolynomials 
780
# End slz_compute_reduced_polynomials_list_from_rows.
781
#
782
def slz_compute_scaled_function(functionSa,
783
                                lowerBoundSa,
784
                                upperBoundSa,
785
                                floatingPointPrecSa,
786
                                debug=False):
787
    """
788
    From a function, compute the scaled function whose domain
789
    is included in [1, 2) and whose image is also included in [1,2).
790
    Return a tuple: 
791
    [0]: the scaled function
792
    [1]: the scaled domain lower bound
793
    [2]: the scaled domain upper bound
794
    [3]: the scaled image lower bound
795
    [4]: the scaled image upper bound
796
    """
797
    ## The variable can be called anything.
798
    x = functionSa.variables()[0]
799
    # Scalling the domain -> [1,2[.
800
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
801
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
802
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
803
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
804
    if debug:
805
        print "domainScalingExpression for argument :", \
806
        invDomainScalingExpressionSa
807
        print "function: ", functionSa
808
    ff = functionSa.subs({x : domainScalingExpressionSa})
809
    ## Bless expression as a function.
810
    ff = ff.function(x)
811
    #ff = f.subs_expr(x==domainScalingExpressionSa)
812
    #domainScalingFunction(x) = invDomainScalingExpressionSa
813
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
814
    scaledLowerBoundSa = \
815
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
816
    scaledUpperBoundSa = \
817
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
818
    if debug:
819
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
820
              scaledUpperBoundSa
821
    #
822
    # Scalling the image -> [1,2[.
823
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
824
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
825
    if flbSa <= fubSa: # Increasing
826
        imageBinadeBottomSa = floor(flbSa.log2())
827
    else: # Decreasing
828
        imageBinadeBottomSa = floor(fubSa.log2())
829
    if debug:
830
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
831
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
832
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
833
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
834
    if debug:
835
        print "imageScalingExpression for argument :", \
836
              invImageScalingExpressionSa
837
    iis = invImageScalingExpressionSa.function(x)
838
    fff = iis.subs({x:ff})
839
    if debug:
840
        print "fff:", fff,
841
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
842
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
843
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
844
# End slz_compute_scaled_function
845

    
846
def slz_fix_bounds_for_binades(lowerBound, 
847
                               upperBound, 
848
                               func = None, 
849
                               domainDirection = -1,
850
                               imageDirection  = -1):
851
    """
852
    Assuming the function is increasing or decreasing over the 
853
    [lowerBound, upperBound] interval, return a lower bound lb and 
854
    an upper bound ub such that:
855
    - lb and ub belong to the same binade;
856
    - func(lb) and func(ub) belong to the same binade.
857
    domainDirection indicate how bounds move to fit into the same binade:
858
    - a negative value move the upper bound down;
859
    - a positive value move the lower bound up.
860
    imageDirection indicate how bounds move in order to have their image
861
    fit into the same binade, variation of the function is also condidered.
862
    For an increasing function:
863
    - negative value moves the upper bound down (and its image value as well);
864
    - a positive values moves the lower bound up (and its image value as well);
865
    For a decreasing function it is the other way round.
866
    """
867
    ## Arguments check
868
    if lowerBound > upperBound:
869
        return None
870
    if lowerBound == upperBound:
871
        return (lowerBound, upperBound)
872
    if func is None:
873
        return None
874
    #
875
    #varFunc = func.variables()[0]
876
    lb = lowerBound
877
    ub = upperBound
878
    lbBinade = slz_compute_binade(lb) 
879
    ubBinade = slz_compute_binade(ub)
880
    ## Domain binade.
881
    while lbBinade != ubBinade:
882
        newIntervalWidth = (ub - lb) / 2
883
        if domainDirection < 0:
884
            ub = lb + newIntervalWidth
885
            ubBinade = slz_compute_binade(ub)
886
        else:
887
            lb = lb + newIntervalWidth
888
            lbBinade = slz_compute_binade(lb) 
889
    ## Image binade.
890
    if lb == ub:
891
        return (lb, ub)
892
    lbImg = func(lb)
893
    ubImg = func(ub)
894
    funcIsInc = (ubImg >= lbImg)
895
    lbImgBinade = slz_compute_binade(lbImg)
896
    ubImgBinade = slz_compute_binade(ubImg)
897
    while lbImgBinade != ubImgBinade:
898
        newIntervalWidth = (ub - lb) / 2
899
        if imageDirection < 0:
900
            if funcIsInc:
901
                ub = lb + newIntervalWidth
902
                ubImgBinade = slz_compute_binade(func(ub))
903
                #print ubImgBinade
904
            else:
905
                lb = lb + newIntervalWidth
906
                lbImgBinade = slz_compute_binade(func(lb))
907
                #print lbImgBinade
908
        else:
909
            if funcIsInc:
910
                lb = lb + newIntervalWidth
911
                lbImgBinade = slz_compute_binade(func(lb))
912
                #print lbImgBinade
913
            else:
914
                ub = lb + newIntervalWidth
915
                ubImgBinade = slz_compute_binade(func(ub))
916
                #print ubImgBinade
917
    # End while lbImgBinade != ubImgBinade:
918
    return (lb, ub)
919
# End slz_fix_bounds_for_binades.
920

    
921
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
922
    # Create a polynomial over the rationals.
923
    ratPolynomialRing = QQ[str(polyOfFloat.variables()[0])]
924
    return(ratPolynomialRing(polyOfFloat))
925
# End slz_float_poly_of_float_to_rat_poly_of_rat.
926

    
927
def slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(polyOfFloat):
928
    """
929
     Create a polynomial over the rationals where all denominators are
930
     powers of two.
931
    """
932
    polyVariable = polyOfFloat.variables()[0] 
933
    RPR = QQ[str(polyVariable)]
934
    polyCoeffs      = polyOfFloat.coefficients()
935
    #print polyCoeffs
936
    polyExponents   = polyOfFloat.exponents()
937
    #print polyExponents
938
    polyDenomPtwoCoeffs = []
939
    for coeff in polyCoeffs:
940
        polyDenomPtwoCoeffs.append(sno_float_to_rat_pow_of_two_denom(coeff))
941
        #print "Converted coefficient:", sno_float_to_rat_pow_of_two_denom(coeff),
942
        #print type(sno_float_to_rat_pow_of_two_denom(coeff))
943
    ratPoly = RPR(0)
944
    #print type(ratPoly)
945
    ## !!! CAUTION !!! Do not use the RPR(coeff * polyVariagle^exponent)
946
    #  The coefficient becomes plainly wrong when exponent == 0.
947
    #  No clue as to why.
948
    for coeff, exponent in zip(polyDenomPtwoCoeffs, polyExponents):
949
        ratPoly += coeff * RPR(polyVariable^exponent)
950
    return ratPoly
951
# End slz_float_poly_of_float_to_rat_poly_of_rat.
952

    
953
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
954
                                      lowerBoundSa, 
955
                                      upperBoundSa, floatingPointPrecSa, 
956
                                      internalSollyaPrecSa, approxPrecSa):
957
    """
958
    Under the assumption that:
959
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
960
    - lowerBound and upperBound belong to the same binade.
961
    from a:
962
    - function;
963
    - a degree
964
    - a pair of bounds;
965
    - the floating-point precision we work on;
966
    - the internal Sollya precision;
967
    - the requested approximation error
968
    The initial interval is, possibly, splitted into smaller intervals.
969
    It return a list of tuples, each made of:
970
    - a first polynomial (without the changed variable f(x) = p(x-x0));
971
    - a second polynomial (with a changed variable f(x) = q(x))
972
    - the approximation interval;
973
    - the center, x0, of the interval;
974
    - the corresponding approximation error.
975
    TODO: fix endless looping for some parameters sets.
976
    """
977
    resultArray = []
978
    # Set Sollya to the necessary internal precision.
979
    precChangedSa = False
980
    currentSollyaPrecSo = pobyso_get_prec_so()
981
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
982
    if internalSollyaPrecSa > currentSollyaPrecSa:
983
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
984
        precChangedSa = True
985
    #
986
    x = functionSa.variables()[0] # Actual variable name can be anything.
987
    # Scaled function: [1=,2] -> [1,2].
988
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
989
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
990
                slz_compute_scaled_function(functionSa,                       \
991
                                            lowerBoundSa,                     \
992
                                            upperBoundSa,                     \
993
                                            floatingPointPrecSa)
994
    # In case bounds were in the negative real one may need to
995
    # switch scaled bounds.
996
    if scaledLowerBoundSa > scaledUpperBoundSa:
997
        scaledLowerBoundSa, scaledUpperBoundSa = \
998
            scaledUpperBoundSa, scaledLowerBoundSa
999
        #print "Switching!"
1000
    print "Approximation precision: ", RR(approxPrecSa)
1001
    # Prepare the arguments for the Taylor expansion computation with Sollya.
1002
    functionSo = \
1003
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
1004
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
1005
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
1006
                                                  scaledUpperBoundSa)
1007

    
1008
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
1009
                                              upperBoundSa.parent().precision()))
1010
    currentScaledLowerBoundSa = scaledLowerBoundSa
1011
    currentScaledUpperBoundSa = scaledUpperBoundSa
1012
    while True:
1013
        ## Compute the first Taylor expansion.
1014
        print "Computing a Taylor expansion..."
1015
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
1016
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
1017
                                        currentScaledLowerBoundSa, 
1018
                                        currentScaledUpperBoundSa,
1019
                                        approxPrecSa, internalSollyaPrecSa)
1020
        print "...done."
1021
        ## If slz_compute_polynomial_and_interval fails, it returns None.
1022
        #  This value goes to the first variable: polySo. Other variables are
1023
        #  not assigned and should not be tested.
1024
        if polySo is None:
1025
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
1026
            if precChangedSa:
1027
                pobyso_set_prec_so_so(currentSollyaPrecSo)
1028
                sollya_lib_clear_obj(currentSollyaPrecSo)
1029
            sollya_lib_clear_obj(functionSo)
1030
            sollya_lib_clear_obj(degreeSo)
1031
            sollya_lib_clear_obj(scaledBoundsSo)
1032
            return None
1033
        ## Add to the result array.
1034
        ### Change variable stuff in Sollya x -> x0-x.
1035
        changeVarExpressionSo = \
1036
            sollya_lib_build_function_sub( \
1037
                              sollya_lib_build_function_free_variable(), 
1038
                              sollya_lib_copy_obj(intervalCenterSo))
1039
        polyVarChangedSo = \
1040
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
1041
        #### Get rid of the variable change Sollya stuff. 
1042
        sollya_lib_clear_obj(changeVarExpressionSo)
1043
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
1044
                            intervalCenterSo, maxErrorSo))
1045
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
1046
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1047
        print "Computed approximation error:", errorSa.n(digits=10)
1048
        # If the error and interval are OK a the first try, just return.
1049
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
1050
            (errorSa <= approxPrecSa):
1051
            if precChangedSa:
1052
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
1053
            sollya_lib_clear_obj(currentSollyaPrecSo)
1054
            sollya_lib_clear_obj(functionSo)
1055
            sollya_lib_clear_obj(degreeSo)
1056
            sollya_lib_clear_obj(scaledBoundsSo)
1057
            #print "Approximation error:", errorSa
1058
            return resultArray
1059
        ## The returned interval upper bound does not reach the requested upper
1060
        #  upper bound: compute the next upper bound.
1061
        ## The following ratio is always >= 1. If errorSa, we may want to
1062
        #  enlarge the interval
1063
        currentErrorRatio = approxPrecSa / errorSa
1064
        ## --|--------------------------------------------------------------|--
1065
        #  --|--------------------|--------------------------------------------
1066
        #  --|----------------------------|------------------------------------
1067
        ## Starting point for the next upper bound.
1068
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
1069
        # Compute the increment. 
1070
        newBoundsWidthSa = \
1071
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
1072
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
1073
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
1074
        # Take into account the original interval upper bound.                     
1075
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
1076
            currentScaledUpperBoundSa = scaledUpperBoundSa
1077
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
1078
            print "Can't shrink the interval anymore!"
1079
            print "You should consider increasing the Sollya internal precision"
1080
            print "or the polynomial degree."
1081
            print "Giving up!"
1082
            if precChangedSa:
1083
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
1084
            sollya_lib_clear_obj(currentSollyaPrecSo)
1085
            sollya_lib_clear_obj(functionSo)
1086
            sollya_lib_clear_obj(degreeSo)
1087
            sollya_lib_clear_obj(scaledBoundsSo)
1088
            return None
1089
        # Compute the other expansions.
1090
        # Test for insufficient precision.
1091
# End slz_get_intervals_and_polynomials
1092

    
1093
def slz_interval_scaling_expression(boundsInterval, expVar):
1094
    """
1095
    Compute the scaling expression to map an interval that spans at most
1096
    a single binade into [1, 2) and the inverse expression as well.
1097
    If the interval spans more than one binade, result is wrong since
1098
    scaling is only based on the lower bound.
1099
    Not very sure that the transformation makes sense for negative numbers.
1100
    """
1101
    # The "one of the bounds is 0" special case. Here we consider
1102
    # the interval as the subnormals binade.
1103
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
1104
        # The upper bound is (or should be) positive.
1105
        if boundsInterval.endpoints()[0] == 0:
1106
            if boundsInterval.endpoints()[1] == 0:
1107
                return None
1108
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
1109
            l2     = boundsInterval.endpoints()[1].abs().log2()
1110
            # The upper bound is a power of two
1111
            if binade == l2:
1112
                scalingCoeff    = 2^(-binade)
1113
                invScalingCoeff = 2^(binade)
1114
                scalingOffset   = 1
1115
                return \
1116
                  ((scalingCoeff * expVar + scalingOffset).function(expVar),
1117
                  ((expVar - scalingOffset) * invScalingCoeff).function(expVar))
1118
            else:
1119
                scalingCoeff    = 2^(-binade-1)
1120
                invScalingCoeff = 2^(binade+1)
1121
                scalingOffset   = 1
1122
                return((scalingCoeff * expVar + scalingOffset),\
1123
                    ((expVar - scalingOffset) * invScalingCoeff))
1124
        # The lower bound is (or should be) negative.
1125
        if boundsInterval.endpoints()[1] == 0:
1126
            if boundsInterval.endpoints()[0] == 0:
1127
                return None
1128
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
1129
            l2     = boundsInterval.endpoints()[0].abs().log2()
1130
            # The upper bound is a power of two
1131
            if binade == l2:
1132
                scalingCoeff    = -2^(-binade)
1133
                invScalingCoeff = -2^(binade)
1134
                scalingOffset   = 1
1135
                return((scalingCoeff * expVar + scalingOffset),\
1136
                    ((expVar - scalingOffset) * invScalingCoeff))
1137
            else:
1138
                scalingCoeff    = -2^(-binade-1)
1139
                invScalingCoeff = -2^(binade+1)
1140
                scalingOffset   = 1
1141
                return((scalingCoeff * expVar + scalingOffset),\
1142
                   ((expVar - scalingOffset) * invScalingCoeff))
1143
    # General case
1144
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
1145
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
1146
    # We allow for a single exception in binade spanning is when the
1147
    # "outward bound" is a power of 2 and its binade is that of the
1148
    # "inner bound" + 1.
1149
    if boundsInterval.endpoints()[0] > 0:
1150
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
1151
        if lbBinade != ubBinade:
1152
            print "Different binades."
1153
            if ubL2 != ubBinade:
1154
                print "Not a power of 2."
1155
                return None
1156
            elif abs(ubBinade - lbBinade) > 1:
1157
                print "Too large span:", abs(ubBinade - lbBinade)
1158
                return None
1159
    else:
1160
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
1161
        if lbBinade != ubBinade:
1162
            print "Different binades."
1163
            if lbL2 != lbBinade:
1164
                print "Not a power of 2."
1165
                return None
1166
            elif abs(ubBinade - lbBinade) > 1:
1167
                print "Too large span:", abs(ubBinade - lbBinade)
1168
                return None
1169
    #print "Lower bound binade:", binade
1170
    if boundsInterval.endpoints()[0] > 0:
1171
        return \
1172
            ((2^(-lbBinade) * expVar).function(expVar),
1173
             (2^(lbBinade) * expVar).function(expVar))
1174
    else:
1175
        return \
1176
            ((-(2^(-ubBinade)) * expVar).function(expVar),
1177
             (-(2^(ubBinade)) * expVar).function(expVar))
1178
"""
1179
    # Code sent to attic. Should be the base for a 
1180
    # "slz_interval_translate_expression" rather than scale.
1181
    # Extra control and special cases code  added in  
1182
    # slz_interval_scaling_expression could (should ?) be added to
1183
    # this new function.
1184
    # The scaling offset is only used for negative numbers.
1185
    # When the absolute value of the lower bound is < 0.
1186
    if abs(boundsInterval.endpoints()[0]) < 1:
1187
        if boundsInterval.endpoints()[0] >= 0:
1188
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1189
            invScalingCoeff = 1/scalingCoeff
1190
            return((scalingCoeff * expVar, 
1191
                    invScalingCoeff * expVar))
1192
        else:
1193
            scalingCoeff = \
1194
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
1195
            scalingOffset = -3 * scalingCoeff
1196
            return((scalingCoeff * expVar + scalingOffset,
1197
                    1/scalingCoeff * expVar + 3))
1198
    else: 
1199
        if boundsInterval.endpoints()[0] >= 0:
1200
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1201
            scalingOffset = 0
1202
            return((scalingCoeff * expVar, 
1203
                    1/scalingCoeff * expVar))
1204
        else:
1205
            scalingCoeff = \
1206
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1207
            scalingOffset =  -3 * scalingCoeff
1208
            #scalingOffset = 0
1209
            return((scalingCoeff * expVar + scalingOffset,
1210
                    1/scalingCoeff * expVar + 3))
1211
"""
1212
# End slz_interval_scaling_expression
1213
   
1214
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1215
    """
1216
    Compute the Sage version of the Taylor polynomial and it's
1217
    companion data (interval, center...)
1218
    The input parameter is a five elements tuple:
1219
    - [0]: the polyomial (without variable change), as polynomial over a
1220
           real ring;
1221
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1222
           over a real ring;
1223
    - [2]: the interval (as Sollya range);
1224
    - [3]: the interval center;
1225
    - [4]: the approximation error. 
1226
    
1227
    The function return a 5 elements tuple: formed with all the 
1228
    input elements converted into their Sollya counterpart.
1229
    """
1230
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
1231
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
1232
    intervalSa = \
1233
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1234
    centerSa = \
1235
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1236
    errorSa = \
1237
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1238
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1239
    # End slz_interval_and_polynomial_to_sage
1240

    
1241
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None, 
1242
            targetPlusOnePrecRF = None, quasiExactRF = None):
1243
    """
1244
      Check if an element (argument) of the domain of function (function)
1245
      yields a HTRN case (rounding to next) for the target precision 
1246
      (as impersonated by targetRF) for a given accuracy (targetAccuracy). 
1247
      
1248
      The strategy is: 
1249
      - compute the image at high (quasi-exact) precision;
1250
      - round it to nearest to precision;
1251
      - round it to exactly to (precision+1), the computed number has two
1252
        midpoint neighbors;
1253
      - check the distance between these neighbors and the quasi-exact value;
1254
        - if none of them is closer than the targetAccuracy, return False,
1255
        - else return true.
1256
      - Powers of two are a special case when comparing the midpoint in
1257
        the 0 direction..
1258
    """
1259
    ## Arguments filtering. 
1260
    ## TODO: filter the first argument for consistence.
1261
    if targetRF is None:
1262
        targetRF = argument.parent()
1263
    ## Ditto for the real field holding the midpoints.
1264
    if targetPlusOnePrecRF is None:
1265
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1266
    ## If no quasiExactField is provided, create a high accuracy RealField.
1267
    if quasiExactRF is None:
1268
        quasiExactRF = RealField(1536)
1269
    function                      = function.function(function.variables()[0])
1270
    exactArgument                 = quasiExactRF(argument)
1271
    quasiExactValue               = function(exactArgument)
1272
    roundedValue                  = targetRF(quasiExactValue)
1273
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1274
    # Upper midpoint.
1275
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1276
    # Lower midpoint.
1277
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1278
    binade                        = slz_compute_binade(roundedValue)
1279
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1280
    #print "Argument:", argument
1281
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1282
    #print "Binade:", binade
1283
    #print "binadeCorrectedTargetAccuracy:", \
1284
    #binadeCorrectedTargetAccuracy.n(prec=100)
1285
    #print "binadeCorrectedTargetAccuracy:", \
1286
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1287
    #print "Upper midpoint:", \
1288
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1289
    #print "Rounded value :", \
1290
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1291
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1292
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1293
    #print "Lower midpoint:", \
1294
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1295
    ## Make quasiExactValue = 0 a special case to move it out of the way.
1296
    if quasiExactValue == 0:
1297
        return False
1298
    ## Begining of the general case : check with the midpoint of 
1299
    #  greatest absolute value.
1300
    if quasiExactValue > 0:
1301
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1302
           binadeCorrectedTargetAccuracy:
1303
            #print "Too close to the upper midpoint: ", \
1304
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1305
            #print argument.n().str(base=16, \
1306
            #  no_sci=False)
1307
            #print "Lower midpoint:", \
1308
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1309
            #print "Value         :", \
1310
            # quasiExactValue.n(prec=200).str(base=2)
1311
            #print "Upper midpoint:", \
1312
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1313
            return True
1314
    else: # quasiExactValue < 0, the 0 case has been previously filtered out.
1315
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1316
           binadeCorrectedTargetAccuracy:
1317
            #print "Too close to the upper midpoint: ", \
1318
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1319
            #print argument.n().str(base=16, \
1320
            #  no_sci=False)
1321
            #print "Lower midpoint:", \
1322
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1323
            #print "Value         :", \
1324
            #  quasiExactValue.n(prec=200).str(base=2)
1325
            #print "Upper midpoint:", \
1326
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1327
            #print
1328
            return True
1329
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1330
    ## For the midpoint of smaller absolute value, 
1331
    #  split cases with the powers of 2.
1332
    if sno_abs_is_power_of_two(roundedValue):
1333
        if quasiExactValue > 0:        
1334
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1335
               binadeCorrectedTargetAccuracy / 2:
1336
                #print "Lower midpoint:", \
1337
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1338
                #print "Value         :", \
1339
                #  quasiExactValue.n(prec=200).str(base=2)
1340
                #print "Upper midpoint:", \
1341
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1342
                #print
1343
                return True
1344
        else:
1345
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1346
              binadeCorrectedTargetAccuracy / 2:
1347
                #print "Lower midpoint:", \
1348
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1349
                #print "Value         :", 
1350
                #  quasiExactValue.n(prec=200).str(base=2)
1351
                #print "Upper midpoint:", 
1352
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1353
                #print
1354
                return True
1355
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1356
    else: ## Not a power of 2, regular comparison with the midpoint of 
1357
          #  smaller absolute value.
1358
        if quasiExactValue > 0:        
1359
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1360
              binadeCorrectedTargetAccuracy:
1361
                #print "Lower midpoint:", \
1362
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1363
                #print "Value         :", \
1364
                #  quasiExactValue.n(prec=200).str(base=2)
1365
                #print "Upper midpoint:", \
1366
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1367
                #print
1368
                return True
1369
        else: # quasiExactValue <= 0
1370
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1371
              binadeCorrectedTargetAccuracy:
1372
                #print "Lower midpoint:", \
1373
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1374
                #print "Value         :", \
1375
                #  quasiExactValue.n(prec=200).str(base=2)
1376
                #print "Upper midpoint:", \
1377
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1378
                #print
1379
                return True
1380
    #print "distance to the upper midpoint:", \
1381
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1382
    #print "distance to the lower midpoint:", \
1383
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1384
    return False
1385
# End slz_is_htrn
1386

    
1387
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
1388
                                                precision,
1389
                                                targetHardnessToRound,
1390
                                                variable1,
1391
                                                variable2):
1392
    """
1393
    Creates a new multivariate polynomial with integer coefficients for use
1394
     with the Coppersmith method.
1395
    A the same time it computes :
1396
    - 2^K (N);
1397
    - 2^k (bound on the second variable)
1398
    - lcm
1399

    
1400
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1401
                         variables.
1402
    :param precision: the precision of the floating-point coefficients.
1403
    :param targetHardnessToRound: the hardness to round we want to check.
1404
    :param variable1: the first variable of the polynomial (an expression).
1405
    :param variable2: the second variable of the polynomial (an expression).
1406
    
1407
    :returns: a 4 elements tuple:
1408
                - the polynomial;
1409
                - the modulus (N);
1410
                - the t bound;
1411
                - the lcm used to compute the integral coefficients and the 
1412
                  module.
1413
    """
1414
    # Create a new integer polynomial ring.
1415
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1416
    # Coefficients are issued in the increasing power order.
1417
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1418
    # Print the reversed list for debugging.
1419
    #print
1420
    #print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1421
    # Build the list of number we compute the lcm of.
1422
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1423
    #print "Coefficient denominators:", coefficientDenominators
1424
    coefficientDenominators.append(2^precision)
1425
    coefficientDenominators.append(2^(targetHardnessToRound))
1426
    leastCommonMultiple = lcm(coefficientDenominators)
1427
    # Compute the expression corresponding to the new polynomial
1428
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1429
    #print coefficientNumerators
1430
    polynomialExpression = 0
1431
    power = 0
1432
    # Iterate over two lists at the same time, stop when the shorter
1433
    # (is this case coefficientsNumerators) is 
1434
    # exhausted. Both lists are ordered in the order of increasing powers
1435
    # of variable1.
1436
    for numerator, denominator in \
1437
                        zip(coefficientNumerators, coefficientDenominators):
1438
        multiplicator = leastCommonMultiple / denominator 
1439
        newCoefficient = numerator * multiplicator
1440
        polynomialExpression += newCoefficient * variable1^power
1441
        power +=1
1442
    polynomialExpression += - variable2
1443
    return (IP(polynomialExpression),
1444
            leastCommonMultiple / 2^precision, # 2^K aka N.
1445
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1446
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1447
            leastCommonMultiple) # If we want to make test computations.
1448
        
1449
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1450

    
1451
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
1452
                                          precision):
1453
    """
1454
    Makes a variable substitution into the input polynomial so that the output
1455
    polynomial can take integer arguments.
1456
    All variables of the input polynomial "have precision p". That is to say
1457
    that they are rationals with denominator == 2^(precision - 1): 
1458
    x = y/2^(precision - 1).
1459
    We "incorporate" these denominators into the coefficients with, 
1460
    respectively, the "right" power.
1461
    """
1462
    polynomialField = ratPolyOfRat.parent()
1463
    polynomialVariable = ratPolyOfRat.variables()[0]
1464
    #print "The polynomial field is:", polynomialField
1465
    return \
1466
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1467
                                   polynomialVariable/2^(precision-1)}))
1468
    
1469
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1470

    
1471
def slz_reduce_and_test_base(matrixToReduce,
1472
                             nAtAlpha,
1473
                             monomialsCountSqrt):
1474
    """
1475
    Reduces the basis, tests the Coppersmith condition and returns
1476
    a list of rows that comply with the condition.
1477
    """
1478
    ccComplientRowsList = []
1479
    reducedMatrix = matrixToReduce.LLL(None)
1480
    if not reducedMatrix.is_LLL_reduced():
1481
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
1482
    else:
1483
        print "reducedMatrix is actually reduced."
1484
    print "N^alpha:", nAtAlpha.n()
1485
    rowIndex = 0
1486
    for row in reducedMatrix.rows():
1487
        l2Norm = row.norm(2)
1488
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
1489
                monomialsCountSqrt.n(), ". Is vector OK?", 
1490
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
1491
            ccComplientRowsList.append(row)
1492
            print "True"
1493
        else:
1494
            print "False"
1495
    # End for
1496
    return ccComplientRowsList
1497
# End slz_reduce_and_test_base
1498

    
1499
def slz_resultant(poly1, poly2, elimVar):
1500
    """
1501
    Compute the resultant for two polynomials for a given variable
1502
    and return the (poly1, poly2, resultant) if the resultant
1503
    is not 0.
1504
    Return () otherwise.
1505
    """
1506
    polynomialRing0    = poly1.parent()
1507
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1508
    if resultantInElimVar is None:
1509
        return None
1510
    if resultantInElimVar.is_zero():
1511
        return None
1512
    else:
1513
        return resultantInElimVar
1514
# End slz_resultant.
1515
#
1516
def slz_resultant_tuple(poly1, poly2, elimVar):
1517
    """
1518
    Compute the resultant for two polynomials for a given variable
1519
    and return the (poly1, poly2, resultant) if the resultant
1520
    is not 0.
1521
    Return () otherwise.
1522
    """
1523
    polynomialRing0    = poly1.parent()
1524
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1525
    if resultantInElimVar.is_zero():
1526
        return ()
1527
    else:
1528
        return (poly1, poly2, resultantInElimVar)
1529
# End slz_resultant_tuple.
1530
#
1531
print "\t...sageSLZ loaded"