Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (58 ko)

1 115 storres
r"""
2 115 storres
Sage core functions needed for the implementation of SLZ.
3 90 storres
4 115 storres
AUTHORS:
5 115 storres
- S.T. (2013-08): initial version
6 90 storres
7 115 storres
Examples:
8 119 storres
9 119 storres
TODO::
10 90 storres
"""
11 87 storres
print "sageSLZ loading..."
12 115 storres
#
13 115 storres
def slz_check_htr_value(function, htrValue, lowerBound, upperBound, precision, \
14 115 storres
                        degree, targetHardnessToRound, alpha):
15 115 storres
    """
16 115 storres
    Check an Hard-to-round value.
17 124 storres
    TODO::
18 124 storres
    Full rewriting: this is hardly a draft.
19 115 storres
    """
20 115 storres
    polyApproxPrec = targetHardnessToRound + 1
21 115 storres
    polyTargetHardnessToRound = targetHardnessToRound + 1
22 115 storres
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
23 115 storres
    RRR = htrValue.parent()
24 115 storres
    #
25 115 storres
    ## Compute the scaled function.
26 115 storres
    fff = slz_compute_scaled_function(f, lowerBound, upperBound, precision)[0]
27 115 storres
    print "Scaled function:", fff
28 115 storres
    #
29 115 storres
    ## Compute the scaling.
30 115 storres
    boundsIntervalRifSa = RealIntervalField(precision)
31 115 storres
    domainBoundsInterval = boundsIntervalRifSa(lowerBound, upperBound)
32 115 storres
    scalingExpressions = \
33 115 storres
        slz_interval_scaling_expression(domainBoundsInterval, i)
34 115 storres
    #
35 115 storres
    ## Get the polynomials, bounds, etc. for all the interval.
36 115 storres
    resultListOfTuplesOfSo = \
37 115 storres
        slz_get_intervals_and_polynomials(f, degree, lowerBound, upperBound, \
38 115 storres
                                          precision, internalSollyaPrec,\
39 115 storres
                                          2^-(polyApproxPrec))
40 115 storres
    #
41 115 storres
    ## We only want one interval.
42 115 storres
    if len(resultListOfTuplesOfSo) > 1:
43 115 storres
        print "Too many intervals! Aborting!"
44 115 storres
        exit
45 115 storres
    #
46 115 storres
    ## Get the first tuple of Sollya objects as Sage objects.
47 115 storres
    firstTupleSa = \
48 115 storres
        slz_interval_and_polynomial_to_sage(resultListOfTuplesOfSo[0])
49 115 storres
    pobyso_set_canonical_on()
50 115 storres
    #
51 115 storres
    print "Floatting point polynomial:", firstTupleSa[0]
52 115 storres
    print "with coefficients precision:", firstTupleSa[0].base_ring().prec()
53 115 storres
    #
54 115 storres
    ## From a polynomial over a real ring, create a polynomial over the
55 115 storres
    #  rationals ring.
56 115 storres
    rationalPolynomial = \
57 115 storres
        slz_float_poly_of_float_to_rat_poly_of_rat(firstTupleSa[0])
58 115 storres
    print "Rational polynomial:", rationalPolynomial
59 115 storres
    #
60 115 storres
    ## Create a polynomial over the rationals that will take integer
61 115 storres
    # variables instead of rational.
62 115 storres
    rationalPolynomialOfIntegers = \
63 115 storres
        slz_rat_poly_of_rat_to_rat_poly_of_int(rationalPolynomial, precision)
64 115 storres
    print "Type:", type(rationalPolynomialOfIntegers)
65 115 storres
    print "Rational polynomial of integers:", rationalPolynomialOfIntegers
66 115 storres
    #
67 115 storres
    ## Check the rational polynomial of integers variables.
68 115 storres
    # (check against the scaled function).
69 115 storres
    toIntegerFactor = 2^(precision-1)
70 115 storres
    intervalCenterAsIntegerSa = int(firstTupleSa[3] * toIntegerFactor)
71 115 storres
    print "Interval center as integer:", intervalCenterAsIntegerSa
72 115 storres
    lowerBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[0] * \
73 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
74 115 storres
    upperBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[1] * \
75 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
76 115 storres
    print "Lower bound as integer:", lowerBoundAsIntegerSa
77 115 storres
    print "Upper bound as integer:", upperBoundAsIntegerSa
78 115 storres
    print "Image of the lower bound by the scaled function", \
79 115 storres
            fff(firstTupleSa[2].endpoints()[0])
80 115 storres
    print "Image of the lower bound by the approximation polynomial of ints:", \
81 115 storres
            RRR(rationalPolynomialOfIntegers(lowerBoundAsIntegerSa))
82 115 storres
    print "Image of the center by the scaled function", fff(firstTupleSa[3])
83 115 storres
    print "Image of the center by the approximation polynomial of ints:", \
84 115 storres
            RRR(rationalPolynomialOfIntegers(0))
85 115 storres
    print "Image of the upper bound by the scaled function", \
86 115 storres
            fff(firstTupleSa[2].endpoints()[1])
87 115 storres
    print "Image of the upper bound by the approximation polynomial of ints:", \
88 115 storres
            RRR(rationalPolynomialOfIntegers(upperBoundAsIntegerSa))
89 115 storres
90 115 storres
# End slz_check_htr_value.
91 122 storres
92 165 storres
def slz_compute_binade(number):
93 165 storres
    """"
94 165 storres
    For a given number, compute the "binade" that is integer m such that
95 165 storres
    2^m <= number < 2^(m+1). If number == 0 return None.
96 165 storres
    """
97 165 storres
    # Checking the parameter.
98 172 storres
    # The exception construction is used to detect if number is a RealNumber
99 165 storres
    # since not all numbers have
100 165 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
101 165 storres
    try:
102 165 storres
        classTree = [number.__class__] + number.mro()
103 172 storres
        # If the number is not a RealNumber (or offspring thereof) try
104 165 storres
        # to transform it.
105 165 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
106 165 storres
            numberAsRR = RR(number)
107 165 storres
        else:
108 165 storres
            numberAsRR = number
109 165 storres
    except AttributeError:
110 165 storres
        return None
111 165 storres
    # Zero special case.
112 165 storres
    if numberAsRR == 0:
113 165 storres
        return RR(-infinity)
114 165 storres
    else:
115 176 storres
        realField           = numberAsRR.parent()
116 176 storres
        numberLog2          = numberAsRR.abs().log2()
117 176 storres
        floorNumberLog2     = floor(numberLog2)
118 176 storres
        ## Do not get caught by rounding of log2() both ways.
119 176 storres
        ## When numberLog2 is an integer, compare numberAsRR
120 176 storres
        #  with 2^numberLog2.
121 176 storres
        if floorNumberLog2 == numberLog2:
122 176 storres
            if numberAsRR.abs() < realField(2^floorNumberLog2):
123 176 storres
                return floorNumberLog2 - 1
124 176 storres
            else:
125 176 storres
                return floorNumberLog2
126 176 storres
        else:
127 176 storres
            return floorNumberLog2
128 165 storres
# End slz_compute_binade
129 165 storres
130 115 storres
#
131 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
132 119 storres
    """
133 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
134 121 storres
135 121 storres
    NOTE::
136 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
137 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
138 125 storres
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
139 125 storres
        this case from that of "really" invalid arguments.
140 121 storres
141 119 storres
    """
142 121 storres
    # Check the parameters.
143 125 storres
    # RealNumbers or RealNumber offspring only.
144 165 storres
    # The exception construction is necessary since not all objects have
145 125 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
146 124 storres
    try:
147 124 storres
        classTree = [number.__class__] + number.mro()
148 124 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
149 124 storres
            return None
150 124 storres
    except AttributeError:
151 121 storres
        return None
152 121 storres
    # Non zero negative integers only for emin.
153 121 storres
    if emin >= 0 or int(emin) != emin:
154 121 storres
        return None
155 121 storres
    # Non zero positive integers only for emax.
156 121 storres
    if emax <= 0 or int(emax) != emax:
157 121 storres
        return None
158 121 storres
    precision = number.precision()
159 121 storres
    RF  = RealField(precision)
160 125 storres
    if number == 0:
161 125 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
162 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
163 121 storres
    # when computing number.log2().
164 121 storres
    RRF = RealField(max(2048, 2 * precision))
165 121 storres
    # number = 0 special case, the binade bounds are
166 121 storres
    # [0, 2^emin - 2^(emin-precision)]
167 121 storres
    # Begin general case
168 119 storres
    l2 = RRF(number).abs().log2()
169 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
170 121 storres
    if l2 >= emax + 1:
171 121 storres
        if number > 0:
172 125 storres
            return (RF(2^(emax+1)), RF(+infinity) )
173 121 storres
        else:
174 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
175 165 storres
    # Regular case cont'd.
176 119 storres
    offset = int(l2)
177 121 storres
    # number.abs() >= 1.
178 119 storres
    if l2 >= 0:
179 119 storres
        if number >= 0:
180 119 storres
            lb = RF(2^offset)
181 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
182 119 storres
        else: #number < 0
183 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
184 119 storres
            ub = -RF(2^offset)
185 121 storres
    else: # log2 < 0, number.abs() < 1.
186 119 storres
        if l2 < emin: # Denormal
187 121 storres
           # print "Denormal:", l2
188 119 storres
            if number >= 0:
189 119 storres
                lb = RF(0)
190 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
191 119 storres
            else: # number <= 0
192 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
193 119 storres
                ub = RF(0)
194 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
195 119 storres
            if number >= 0:
196 121 storres
                if int(l2) == l2:
197 121 storres
                    lb = RF(2^(offset))
198 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
199 121 storres
                else:
200 121 storres
                    lb = RF(2^(offset-1))
201 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
202 119 storres
            else: # number < 0
203 121 storres
                if int(l2) == l2: # Binade limit.
204 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
205 121 storres
                    ub = -RF(2^(offset))
206 121 storres
                else:
207 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
208 121 storres
                    ub = -RF(2^(offset-1))
209 121 storres
        else: # l2== emin, number == +/-2^emin
210 119 storres
            if number >= 0:
211 119 storres
                lb = RF(2^(offset))
212 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
213 119 storres
            else: # number < 0
214 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
215 119 storres
                ub = -RF(2^(offset))
216 119 storres
    return (lb, ub)
217 119 storres
# End slz_compute_binade_bounds
218 119 storres
#
219 123 storres
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
220 123 storres
                                                 alpha,
221 123 storres
                                                 N,
222 123 storres
                                                 iBound,
223 123 storres
                                                 tBound):
224 123 storres
    """
225 123 storres
    For a given set of arguments (see below), compute a list
226 123 storres
    of "reduced polynomials" that could be used to compute roots
227 123 storres
    of the inputPolynomial.
228 124 storres
    INPUT:
229 124 storres
230 124 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
231 124 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
232 124 storres
    - "N" -- the modulus;
233 124 storres
    - "iBound" -- the bound on the first variable;
234 124 storres
    - "tBound" -- the bound on the second variable.
235 124 storres
236 124 storres
    OUTPUT:
237 124 storres
238 124 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
239 124 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
240 124 storres
    reduced base that comply with the Coppersmith condition.
241 123 storres
    """
242 123 storres
    # Arguments check.
243 123 storres
    if iBound == 0 or tBound == 0:
244 123 storres
        return ()
245 123 storres
    # End arguments check.
246 123 storres
    nAtAlpha = N^alpha
247 123 storres
    ## Building polynomials for matrix.
248 123 storres
    polyRing   = inputPolynomial.parent()
249 123 storres
    # Whatever the 2 variables are actually called, we call them
250 123 storres
    # 'i' and 't' in all the variable names.
251 123 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
252 123 storres
    #print polyVars[0], type(polyVars[0])
253 123 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
254 123 storres
                                              tVariable:tVariable * tBound})
255 123 storres
    polynomialsList = \
256 158 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
257 123 storres
                                             alpha,
258 123 storres
                                             N,
259 123 storres
                                             iBound,
260 123 storres
                                             tBound,
261 123 storres
                                             0)
262 123 storres
    #print "Polynomials list:", polynomialsList
263 123 storres
    ## Building the proto matrix.
264 123 storres
    knownMonomials = []
265 123 storres
    protoMatrix    = []
266 123 storres
    for poly in polynomialsList:
267 123 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
268 123 storres
                                                knownMonomials,
269 123 storres
                                                protoMatrix,
270 123 storres
                                                0)
271 123 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
272 123 storres
    #print matrixToReduce
273 123 storres
    ## Reduction and checking.
274 163 storres
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
275 163 storres
    #  error message issued when previous code was used.
276 163 storres
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
277 163 storres
    reducedMatrix = matrixToReduce.LLL(fp=None)
278 123 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
279 123 storres
    if not isLLLReduced:
280 157 storres
        return ()
281 123 storres
    monomialsCount     = len(knownMonomials)
282 123 storres
    monomialsCountSqrt = sqrt(monomialsCount)
283 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
284 123 storres
    #print reducedMatrix
285 123 storres
    ## Check the Coppersmith condition for each row and build the reduced
286 123 storres
    #  polynomials.
287 123 storres
    ccReducedPolynomialsList = []
288 123 storres
    for row in reducedMatrix.rows():
289 123 storres
        l2Norm = row.norm(2)
290 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
291 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
292 125 storres
            #print l2Norm.n()
293 123 storres
            ccReducedPolynomial = \
294 123 storres
                slz_compute_reduced_polynomial(row,
295 123 storres
                                               knownMonomials,
296 123 storres
                                               iVariable,
297 123 storres
                                               iBound,
298 123 storres
                                               tVariable,
299 123 storres
                                               tBound)
300 123 storres
            if not ccReducedPolynomial is None:
301 123 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
302 123 storres
        else:
303 125 storres
            #print l2Norm.n() , ">", nAtAlpha
304 123 storres
            pass
305 123 storres
    if len(ccReducedPolynomialsList) < 2:
306 125 storres
        print "Less than 2 Coppersmith condition compliant vectors."
307 123 storres
        return ()
308 125 storres
309 125 storres
    #print ccReducedPolynomialsList
310 123 storres
    return ccReducedPolynomialsList
311 123 storres
# End slz_compute_coppersmith_reduced_polynomials
312 123 storres
313 122 storres
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
314 122 storres
                                                 alpha,
315 122 storres
                                                 N,
316 122 storres
                                                 iBound,
317 122 storres
                                                 tBound):
318 122 storres
    """
319 123 storres
    For a given set of arguments (see below), compute the polynomial modular
320 122 storres
    roots, if any.
321 124 storres
322 122 storres
    """
323 123 storres
    # Arguments check.
324 123 storres
    if iBound == 0 or tBound == 0:
325 123 storres
        return set()
326 123 storres
    # End arguments check.
327 122 storres
    nAtAlpha = N^alpha
328 122 storres
    ## Building polynomials for matrix.
329 122 storres
    polyRing   = inputPolynomial.parent()
330 122 storres
    # Whatever the 2 variables are actually called, we call them
331 122 storres
    # 'i' and 't' in all the variable names.
332 122 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
333 125 storres
    ccReducedPolynomialsList = \
334 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
335 125 storres
                                                     alpha,
336 125 storres
                                                     N,
337 125 storres
                                                     iBound,
338 125 storres
                                                     tBound)
339 125 storres
    if len(ccReducedPolynomialsList) == 0:
340 125 storres
        return set()
341 122 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
342 122 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
343 122 storres
    # Try to mix and match all the polynomial pairs built from the
344 122 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
345 122 storres
    resultantsInITuplesList = []
346 122 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
347 122 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
348 122 storres
                                     len(ccReducedPolynomialsList)):
349 122 storres
            # Compute the resultant in resultants in the
350 122 storres
            # first variable (is it the optimal choice?).
351 122 storres
            resultantInI = \
352 122 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
353 122 storres
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
354 122 storres
            #print "Resultant", resultantInI
355 122 storres
            # Test algebraic independence.
356 122 storres
            if not resultantInI.is_zero():
357 122 storres
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
358 122 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
359 122 storres
                                                 resultantInI))
360 122 storres
    # If no non zero resultant was found: we can't get no algebraically
361 122 storres
    # independent polynomials pair. Give up!
362 122 storres
    if len(resultantsInITuplesList) == 0:
363 123 storres
        return set()
364 123 storres
    #print resultantsInITuplesList
365 122 storres
    # Compute the roots.
366 122 storres
    Zi = ZZ[str(iVariable)]
367 122 storres
    Zt = ZZ[str(tVariable)]
368 122 storres
    polynomialRootsSet = set()
369 122 storres
    # First, solve in the second variable since resultants are in the first
370 122 storres
    # variable.
371 122 storres
    for resultantInITuple in resultantsInITuplesList:
372 122 storres
        tRootsList = Zt(resultantInITuple[2]).roots()
373 122 storres
        # For each tRoot, compute the corresponding iRoots and check
374 123 storres
        # them in the input polynomial.
375 122 storres
        for tRoot in tRootsList:
376 123 storres
            #print "tRoot:", tRoot
377 122 storres
            # Roots returned by root() are (value, multiplicity) tuples.
378 122 storres
            iRootsList = \
379 122 storres
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
380 123 storres
            print iRootsList
381 122 storres
            # The iRootsList can be empty, hence the test.
382 122 storres
            if len(iRootsList) != 0:
383 122 storres
                for iRoot in iRootsList:
384 122 storres
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
385 122 storres
                    # polyEvalModN must be an integer.
386 122 storres
                    if polyEvalModN == int(polyEvalModN):
387 122 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
388 122 storres
    return polynomialRootsSet
389 122 storres
# End slz_compute_integer_polynomial_modular_roots.
390 122 storres
#
391 125 storres
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
392 125 storres
                                                 alpha,
393 125 storres
                                                 N,
394 125 storres
                                                 iBound,
395 125 storres
                                                 tBound):
396 125 storres
    """
397 125 storres
    For a given set of arguments (see below), compute the polynomial modular
398 125 storres
    roots, if any.
399 125 storres
    This version differs in the way resultants are computed.
400 125 storres
    """
401 125 storres
    # Arguments check.
402 125 storres
    if iBound == 0 or tBound == 0:
403 125 storres
        return set()
404 125 storres
    # End arguments check.
405 125 storres
    nAtAlpha = N^alpha
406 125 storres
    ## Building polynomials for matrix.
407 125 storres
    polyRing   = inputPolynomial.parent()
408 125 storres
    # Whatever the 2 variables are actually called, we call them
409 125 storres
    # 'i' and 't' in all the variable names.
410 125 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
411 125 storres
    #print polyVars[0], type(polyVars[0])
412 125 storres
    ccReducedPolynomialsList = \
413 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
414 125 storres
                                                     alpha,
415 125 storres
                                                     N,
416 125 storres
                                                     iBound,
417 125 storres
                                                     tBound)
418 125 storres
    if len(ccReducedPolynomialsList) == 0:
419 125 storres
        return set()
420 125 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
421 125 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
422 125 storres
    # Try to mix and match all the polynomial pairs built from the
423 125 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
424 125 storres
    resultantsInTTuplesList = []
425 125 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
426 125 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
427 125 storres
                                     len(ccReducedPolynomialsList)):
428 125 storres
            # Compute the resultant in resultants in the
429 125 storres
            # first variable (is it the optimal choice?).
430 125 storres
            resultantInT = \
431 125 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
432 125 storres
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
433 125 storres
            #print "Resultant", resultantInT
434 125 storres
            # Test algebraic independence.
435 125 storres
            if not resultantInT.is_zero():
436 125 storres
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
437 125 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
438 125 storres
                                                 resultantInT))
439 125 storres
    # If no non zero resultant was found: we can't get no algebraically
440 125 storres
    # independent polynomials pair. Give up!
441 125 storres
    if len(resultantsInTTuplesList) == 0:
442 125 storres
        return set()
443 125 storres
    #print resultantsInITuplesList
444 125 storres
    # Compute the roots.
445 125 storres
    Zi = ZZ[str(iVariable)]
446 125 storres
    Zt = ZZ[str(tVariable)]
447 125 storres
    polynomialRootsSet = set()
448 125 storres
    # First, solve in the second variable since resultants are in the first
449 125 storres
    # variable.
450 125 storres
    for resultantInTTuple in resultantsInTTuplesList:
451 125 storres
        iRootsList = Zi(resultantInTTuple[2]).roots()
452 125 storres
        # For each iRoot, compute the corresponding tRoots and check
453 125 storres
        # them in the input polynomial.
454 125 storres
        for iRoot in iRootsList:
455 125 storres
            #print "iRoot:", iRoot
456 125 storres
            # Roots returned by root() are (value, multiplicity) tuples.
457 125 storres
            tRootsList = \
458 125 storres
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
459 125 storres
            print tRootsList
460 125 storres
            # The tRootsList can be empty, hence the test.
461 125 storres
            if len(tRootsList) != 0:
462 125 storres
                for tRoot in tRootsList:
463 125 storres
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
464 125 storres
                    # polyEvalModN must be an integer.
465 125 storres
                    if polyEvalModN == int(polyEvalModN):
466 125 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
467 125 storres
    return polynomialRootsSet
468 125 storres
# End slz_compute_integer_polynomial_modular_roots_2.
469 125 storres
#
470 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
471 61 storres
                                        upperBoundSa, approxPrecSa,
472 61 storres
                                        sollyaPrecSa=None):
473 61 storres
    """
474 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
475 61 storres
    a polynomial that approximates the function on a an interval starting
476 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
477 61 storres
    approximates with the expected precision.
478 61 storres
    The interval upper bound is lowered until the expected approximation
479 61 storres
    precision is reached.
480 61 storres
    The polynomial, the bounds, the center of the interval and the error
481 61 storres
    are returned.
482 156 storres
    OUTPUT:
483 124 storres
    A tuple made of 4 Sollya objects:
484 124 storres
    - a polynomial;
485 124 storres
    - an range (an interval, not in the sense of number given as an interval);
486 124 storres
    - the center of the interval;
487 124 storres
    - the maximum error in the approximation of the input functionSo by the
488 124 storres
      output polynomial ; this error <= approxPrecSaS.
489 124 storres
490 61 storres
    """
491 166 storres
    ## Superficial argument check.
492 166 storres
    if lowerBoundSa > upperBoundSa:
493 166 storres
        return None
494 61 storres
    RRR = lowerBoundSa.parent()
495 176 storres
    intervalShrinkConstFactorSa = RRR('0.9')
496 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
497 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
498 61 storres
    currentUpperBoundSa = upperBoundSa
499 61 storres
    currentLowerBoundSa = lowerBoundSa
500 61 storres
    # What we want here is the polynomial without the variable change,
501 61 storres
    # since our actual variable will be x-intervalCenter defined over the
502 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
503 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
504 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
505 61 storres
                                                    currentRangeSo,
506 61 storres
                                                    absoluteErrorTypeSo)
507 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
508 61 storres
    while maxErrorSa > approxPrecSa:
509 166 storres
        print "++Approximation error:", maxErrorSa
510 81 storres
        sollya_lib_clear_obj(polySo)
511 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
512 120 storres
        sollya_lib_clear_obj(maxErrorSo)
513 176 storres
        # Very empirical schrinking factor.
514 176 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxPrecSa).log2().abs()
515 176 storres
        print "Shrink factor:", shrinkFactorSa, intervalShrinkConstFactorSa
516 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
517 61 storres
        #print "Error ratio: ", errorRatioSa
518 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
519 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
520 81 storres
            #print "Fixed"
521 61 storres
        else:
522 81 storres
            actualShrinkFactorSa = shrinkFactorSa
523 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
524 81 storres
            #print shrinkFactorSa, maxErrorSa
525 101 storres
        #print "Shrink factor", actualShrinkFactorSa
526 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
527 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
528 81 storres
                                   actualShrinkFactorSa
529 71 storres
        #print "Current upper bound:", currentUpperBoundSa
530 61 storres
        sollya_lib_clear_obj(currentRangeSo)
531 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
532 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
533 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
534 86 storres
            print "Can't find an interval."
535 86 storres
            print "Use either or both a higher polynomial degree or a higher",
536 86 storres
            print "internal precision."
537 86 storres
            print "Aborting!"
538 86 storres
            return (None, None, None, None)
539 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
540 61 storres
                                                      currentUpperBoundSa)
541 86 storres
        # print "New interval:",
542 86 storres
        # pobyso_autoprint(currentRangeSo)
543 120 storres
        #print "Second Taylor expansion call."
544 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
545 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
546 61 storres
                                                        currentRangeSo,
547 61 storres
                                                        absoluteErrorTypeSo)
548 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
549 85 storres
        #print "Max errorSo:",
550 85 storres
        #pobyso_autoprint(maxErrorSo)
551 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
552 85 storres
        #print "Max errorSa:", maxErrorSa
553 85 storres
        #print "Sollya prec:",
554 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
555 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
556 176 storres
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
557 81 storres
# End slz_compute_polynomial_and_interval
558 61 storres
559 122 storres
def slz_compute_reduced_polynomial(matrixRow,
560 98 storres
                                    knownMonomials,
561 106 storres
                                    var1,
562 98 storres
                                    var1Bound,
563 106 storres
                                    var2,
564 99 storres
                                    var2Bound):
565 98 storres
    """
566 125 storres
    Compute a polynomial from a single reduced matrix row.
567 122 storres
    This function was introduced in order to avoid the computation of the
568 125 storres
    all the polynomials  from the full matrix (even those built from rows
569 125 storres
    that do no verify the Coppersmith condition) as this may involves
570 152 storres
    expensive operations over (large) integers.
571 122 storres
    """
572 122 storres
    ## Check arguments.
573 122 storres
    if len(knownMonomials) == 0:
574 122 storres
        return None
575 122 storres
    # varNounds can be zero since 0^0 returns 1.
576 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
577 122 storres
        return None
578 122 storres
    ## Initialisations.
579 122 storres
    polynomialRing = knownMonomials[0].parent()
580 122 storres
    currentPolynomial = polynomialRing(0)
581 123 storres
    # TODO: use zip instead of indices.
582 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
583 122 storres
        currentCoefficient = matrixRow[colIndex]
584 122 storres
        if currentCoefficient != 0:
585 122 storres
            #print "Current coefficient:", currentCoefficient
586 122 storres
            currentMonomial = knownMonomials[colIndex]
587 122 storres
            #print "Monomial as multivariate polynomial:", \
588 122 storres
            #currentMonomial, type(currentMonomial)
589 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
590 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
591 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
592 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
593 122 storres
            if degreeInVar1 > 0:
594 122 storres
                currentCoefficient = \
595 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
596 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
597 122 storres
                #print "Current coefficient(1)", currentCoefficient
598 122 storres
            if degreeInVar2 > 0:
599 122 storres
                currentCoefficient = \
600 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
601 122 storres
                #print "Current coefficient(2)", currentCoefficient
602 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
603 122 storres
            #                                    currentMonomial)
604 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
605 122 storres
            #print "Current polynomial:", currentPolynomial
606 122 storres
        # End if
607 122 storres
    # End for colIndex.
608 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
609 122 storres
    return(currentPolynomial)
610 122 storres
# End slz_compute_reduced_polynomial
611 122 storres
#
612 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
613 122 storres
                                        knownMonomials,
614 122 storres
                                        var1,
615 122 storres
                                        var1Bound,
616 122 storres
                                        var2,
617 122 storres
                                        var2Bound):
618 122 storres
    """
619 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
620 122 storres
    """
621 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
622 122 storres
                                                knownMonomials,
623 122 storres
                                                var1,
624 122 storres
                                                var1Bound,
625 122 storres
                                                var2,
626 122 storres
                                                var2Bound)
627 122 storres
    )
628 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
629 152 storres
                                         knownMonomials,
630 152 storres
                                         var1,
631 152 storres
                                         var1Bound,
632 152 storres
                                         var2,
633 152 storres
                                         var2Bound):
634 122 storres
    """
635 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
636 98 storres
    from the bounds of each variable, compute the corresponding polynomials
637 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
638 99 storres
639 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
640 172 storres
    They set the polynomial type of the output polynomials in list.
641 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
642 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
643 152 storres
                           build the polynomials;
644 152 storres
    @param var1:           the first variable (of the "right" type);
645 152 storres
    @param var1Bound:      the first variable bound;
646 152 storres
    @param var2:           the second variable (of the "right" type);
647 152 storres
    @param var2Bound:      the second variable bound.
648 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
649 152 storres
             and scaled down with the bounds
650 98 storres
    """
651 99 storres
652 98 storres
    # TODO: check input arguments.
653 98 storres
    reducedPolynomials = []
654 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
655 98 storres
    for matrixRow in reducedMatrix.rows():
656 102 storres
        currentPolynomial = 0
657 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
658 98 storres
            currentCoefficient = matrixRow[colIndex]
659 106 storres
            if currentCoefficient != 0:
660 106 storres
                #print "Current coefficient:", currentCoefficient
661 106 storres
                currentMonomial = knownMonomials[colIndex]
662 106 storres
                parentRing = currentMonomial.parent()
663 106 storres
                #print "Monomial as multivariate polynomial:", \
664 106 storres
                #currentMonomial, type(currentMonomial)
665 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
666 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
667 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
668 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
669 106 storres
                if degreeInVar1 > 0:
670 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
671 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
672 106 storres
                    #print "Current coefficient(1)", currentCoefficient
673 106 storres
                if degreeInVar2 > 0:
674 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
675 106 storres
                    #print "Current coefficient(2)", currentCoefficient
676 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
677 106 storres
                #                                    currentMonomial)
678 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
679 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
680 168 storres
                    #print "!!!! constant term !!!!"
681 106 storres
                #print "Current polynomial:", currentPolynomial
682 106 storres
            # End if
683 106 storres
        # End for colIndex.
684 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
685 99 storres
        reducedPolynomials.append(currentPolynomial)
686 98 storres
    return reducedPolynomials
687 99 storres
# End slz_compute_reduced_polynomials.
688 98 storres
689 114 storres
def slz_compute_scaled_function(functionSa,
690 114 storres
                                lowerBoundSa,
691 114 storres
                                upperBoundSa,
692 156 storres
                                floatingPointPrecSa,
693 156 storres
                                debug=False):
694 72 storres
    """
695 72 storres
    From a function, compute the scaled function whose domain
696 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
697 72 storres
    Return a tuple:
698 72 storres
    [0]: the scaled function
699 72 storres
    [1]: the scaled domain lower bound
700 72 storres
    [2]: the scaled domain upper bound
701 72 storres
    [3]: the scaled image lower bound
702 72 storres
    [4]: the scaled image upper bound
703 72 storres
    """
704 80 storres
    x = functionSa.variables()[0]
705 80 storres
    # Reassert f as a function (an not a mere expression).
706 80 storres
707 72 storres
    # Scalling the domain -> [1,2[.
708 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
709 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
710 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
711 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
712 156 storres
    if debug:
713 156 storres
        print "domainScalingExpression for argument :", \
714 156 storres
        invDomainScalingExpressionSa
715 156 storres
        print "f: ", f
716 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
717 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
718 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
719 151 storres
    scaledLowerBoundSa = \
720 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
721 151 storres
    scaledUpperBoundSa = \
722 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
723 156 storres
    if debug:
724 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
725 156 storres
              scaledUpperBoundSa
726 72 storres
    #
727 72 storres
    # Scalling the image -> [1,2[.
728 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
729 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
730 72 storres
    if flbSa <= fubSa: # Increasing
731 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
732 72 storres
    else: # Decreasing
733 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
734 156 storres
    if debug:
735 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
736 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
737 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
738 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
739 156 storres
    if debug:
740 156 storres
        print "imageScalingExpression for argument :", \
741 156 storres
              invImageScalingExpressionSa
742 72 storres
    iis = invImageScalingExpressionSa.function(x)
743 72 storres
    fff = iis.subs({x:ff})
744 156 storres
    if debug:
745 156 storres
        print "fff:", fff,
746 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
747 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
748 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
749 151 storres
# End slz_compute_scaled_function
750 72 storres
751 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
752 79 storres
    # Create a polynomial over the rationals.
753 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
754 79 storres
    return(polynomialRing(polyOfFloat))
755 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
756 81 storres
757 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
758 63 storres
                                      lowerBoundSa,
759 60 storres
                                      upperBoundSa, floatingPointPrecSa,
760 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
761 60 storres
    """
762 60 storres
    Under the assumption that:
763 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
764 60 storres
    - lowerBound and upperBound belong to the same binade.
765 60 storres
    from a:
766 60 storres
    - function;
767 60 storres
    - a degree
768 60 storres
    - a pair of bounds;
769 60 storres
    - the floating-point precision we work on;
770 60 storres
    - the internal Sollya precision;
771 64 storres
    - the requested approximation error
772 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
773 61 storres
    It return a list of tuples, each made of:
774 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
775 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
776 61 storres
    - the approximation interval;
777 72 storres
    - the center, x0, of the interval;
778 61 storres
    - the corresponding approximation error.
779 100 storres
    TODO: fix endless looping for some parameters sets.
780 60 storres
    """
781 120 storres
    resultArray = []
782 101 storres
    # Set Sollya to the necessary internal precision.
783 120 storres
    precChangedSa = False
784 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
785 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
786 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
787 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
788 120 storres
        precChangedSa = True
789 101 storres
    #
790 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
791 101 storres
    # Scaled function: [1=,2] -> [1,2].
792 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
793 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
794 115 storres
                slz_compute_scaled_function(functionSa,                       \
795 115 storres
                                            lowerBoundSa,                     \
796 115 storres
                                            upperBoundSa,                     \
797 80 storres
                                            floatingPointPrecSa)
798 166 storres
    # In case bounds were in the negative real one may need to
799 166 storres
    # switch scaled bounds.
800 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
801 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
802 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
803 166 storres
        #print "Switching!"
804 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
805 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
806 159 storres
    functionSo = \
807 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
808 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
809 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
810 61 storres
                                                  scaledUpperBoundSa)
811 176 storres
812 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
813 60 storres
                                              upperBoundSa.parent().precision()))
814 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
815 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
816 176 storres
    while True:
817 176 storres
        ## Compute the first Taylor expansion.
818 176 storres
        print "Computing a Taylor expansion..."
819 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
820 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
821 176 storres
                                        currentScaledLowerBoundSa,
822 176 storres
                                        currentScaledUpperBoundSa,
823 176 storres
                                        approxPrecSa, internalSollyaPrecSa)
824 176 storres
        print "...done."
825 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
826 176 storres
        #  This value goes to the first variable: polySo. Other variables are
827 176 storres
        #  not assigned and should not be tested.
828 176 storres
        if polySo is None:
829 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
830 176 storres
            if precChangedSa:
831 176 storres
                pobyso_set_prec_so_so(currentSollyaPrecSo)
832 176 storres
                sollya_lib_clear_obj(currentSollyaPrecSo)
833 176 storres
            sollya_lib_clear_obj(functionSo)
834 176 storres
            sollya_lib_clear_obj(degreeSo)
835 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
836 176 storres
            return None
837 176 storres
        ## Add to the result array.
838 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
839 176 storres
        changeVarExpressionSo = \
840 176 storres
            sollya_lib_build_function_sub( \
841 176 storres
                              sollya_lib_build_function_free_variable(),
842 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
843 176 storres
        polyVarChangedSo = \
844 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
845 176 storres
        #### Get rid of the variable change Sollya stuff.
846 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
847 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
848 101 storres
                            intervalCenterSo, maxErrorSo))
849 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
850 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
851 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
852 176 storres
        # If the error and interval are OK a the first try, just return.
853 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
854 176 storres
            (errorSa <= approxPrecSa):
855 176 storres
            if precChangedSa:
856 176 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
857 176 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
858 176 storres
            sollya_lib_clear_obj(functionSo)
859 176 storres
            sollya_lib_clear_obj(degreeSo)
860 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
861 101 storres
            #print "Approximation error:", errorSa
862 176 storres
            return resultArray
863 176 storres
        ## The returned interval upper bound does not reach the requested upper
864 176 storres
        #  upper bound: compute the next upper bound.
865 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
866 176 storres
        #  enlarge the interval
867 81 storres
        currentErrorRatio = approxPrecSa / errorSa
868 176 storres
        ## --|--------------------------------------------------------------|--
869 176 storres
        #  --|--------------------|--------------------------------------------
870 176 storres
        #  --|----------------------------|------------------------------------
871 176 storres
        ## Starting point for the next upper bound.
872 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
873 101 storres
        # Compute the increment.
874 176 storres
        newBoundsWidthSa = \
875 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
876 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
877 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
878 176 storres
        # Take into account the original interval upper bound.
879 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
880 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
881 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
882 85 storres
            print "Can't shrink the interval anymore!"
883 85 storres
            print "You should consider increasing the Sollya internal precision"
884 85 storres
            print "or the polynomial degree."
885 85 storres
            print "Giving up!"
886 176 storres
            if precChangedSa:
887 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
888 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
889 85 storres
            sollya_lib_clear_obj(functionSo)
890 85 storres
            sollya_lib_clear_obj(degreeSo)
891 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
892 85 storres
            return None
893 176 storres
        # Compute the other expansions.
894 176 storres
        # Test for insufficient precision.
895 81 storres
# End slz_get_intervals_and_polynomials
896 60 storres
897 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
898 61 storres
    """
899 151 storres
    Compute the scaling expression to map an interval that spans at most
900 166 storres
    a single binade into [1, 2) and the inverse expression as well.
901 165 storres
    If the interval spans more than one binade, result is wrong since
902 165 storres
    scaling is only based on the lower bound.
903 62 storres
    Not very sure that the transformation makes sense for negative numbers.
904 61 storres
    """
905 165 storres
    # The "one of the bounds is 0" special case. Here we consider
906 165 storres
    # the interval as the subnormals binade.
907 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
908 165 storres
        # The upper bound is (or should be) positive.
909 165 storres
        if boundsInterval.endpoints()[0] == 0:
910 165 storres
            if boundsInterval.endpoints()[1] == 0:
911 165 storres
                return None
912 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
913 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
914 165 storres
            # The upper bound is a power of two
915 165 storres
            if binade == l2:
916 165 storres
                scalingCoeff    = 2^(-binade)
917 165 storres
                invScalingCoeff = 2^(binade)
918 165 storres
                scalingOffset   = 1
919 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
920 165 storres
                       ((expVar - scalingOffset) * invScalingCoeff))
921 165 storres
            else:
922 165 storres
                scalingCoeff    = 2^(-binade-1)
923 165 storres
                invScalingCoeff = 2^(binade+1)
924 165 storres
                scalingOffset   = 1
925 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
926 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
927 165 storres
        # The lower bound is (or should be) negative.
928 165 storres
        if boundsInterval.endpoints()[1] == 0:
929 165 storres
            if boundsInterval.endpoints()[0] == 0:
930 165 storres
                return None
931 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
932 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
933 165 storres
            # The upper bound is a power of two
934 165 storres
            if binade == l2:
935 165 storres
                scalingCoeff    = -2^(-binade)
936 165 storres
                invScalingCoeff = -2^(binade)
937 165 storres
                scalingOffset   = 1
938 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
939 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
940 165 storres
            else:
941 165 storres
                scalingCoeff    = -2^(-binade-1)
942 165 storres
                invScalingCoeff = -2^(binade+1)
943 165 storres
                scalingOffset   = 1
944 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
945 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
946 165 storres
    # General case
947 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
948 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
949 165 storres
    # We allow for a single exception in binade spanning is when the
950 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
951 165 storres
    # "inner bound" + 1.
952 165 storres
    if boundsInterval.endpoints()[0] > 0:
953 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
954 165 storres
        if lbBinade != ubBinade:
955 165 storres
            print "Different binades."
956 165 storres
            if ubL2 != ubBinade:
957 165 storres
                print "Not a power of 2."
958 165 storres
                return None
959 165 storres
            elif abs(ubBinade - lbBinade) > 1:
960 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
961 165 storres
                return None
962 165 storres
    else:
963 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
964 165 storres
        if lbBinade != ubBinade:
965 165 storres
            print "Different binades."
966 165 storres
            if lbL2 != lbBinade:
967 165 storres
                print "Not a power of 2."
968 165 storres
                return None
969 165 storres
            elif abs(ubBinade - lbBinade) > 1:
970 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
971 165 storres
                return None
972 165 storres
    #print "Lower bound binade:", binade
973 165 storres
    if boundsInterval.endpoints()[0] > 0:
974 165 storres
        return((2^(-lbBinade) * expVar),(2^(lbBinade) * expVar))
975 165 storres
    else:
976 166 storres
        return((-(2^(-ubBinade)) * expVar),(-(2^(ubBinade)) * expVar))
977 165 storres
"""
978 165 storres
    # Code sent to attic. Should be the base for a
979 165 storres
    # "slz_interval_translate_expression" rather than scale.
980 165 storres
    # Extra control and special cases code  added in
981 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
982 165 storres
    # this new function.
983 62 storres
    # The scaling offset is only used for negative numbers.
984 151 storres
    # When the absolute value of the lower bound is < 0.
985 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
986 61 storres
        if boundsInterval.endpoints()[0] >= 0:
987 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
988 62 storres
            invScalingCoeff = 1/scalingCoeff
989 80 storres
            return((scalingCoeff * expVar,
990 80 storres
                    invScalingCoeff * expVar))
991 60 storres
        else:
992 62 storres
            scalingCoeff = \
993 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
994 62 storres
            scalingOffset = -3 * scalingCoeff
995 80 storres
            return((scalingCoeff * expVar + scalingOffset,
996 80 storres
                    1/scalingCoeff * expVar + 3))
997 61 storres
    else:
998 61 storres
        if boundsInterval.endpoints()[0] >= 0:
999 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1000 61 storres
            scalingOffset = 0
1001 80 storres
            return((scalingCoeff * expVar,
1002 80 storres
                    1/scalingCoeff * expVar))
1003 61 storres
        else:
1004 62 storres
            scalingCoeff = \
1005 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1006 62 storres
            scalingOffset =  -3 * scalingCoeff
1007 62 storres
            #scalingOffset = 0
1008 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1009 80 storres
                    1/scalingCoeff * expVar + 3))
1010 165 storres
"""
1011 151 storres
# End slz_interval_scaling_expression
1012 61 storres
1013 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1014 72 storres
    """
1015 72 storres
    Compute the Sage version of the Taylor polynomial and it's
1016 72 storres
    companion data (interval, center...)
1017 72 storres
    The input parameter is a five elements tuple:
1018 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1019 79 storres
           real ring;
1020 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1021 79 storres
           over a real ring;
1022 72 storres
    - [2]: the interval (as Sollya range);
1023 72 storres
    - [3]: the interval center;
1024 72 storres
    - [4]: the approximation error.
1025 72 storres
1026 72 storres
    The function return a 5 elements tuple: formed with all the
1027 72 storres
    input elements converted into their Sollya counterpart.
1028 72 storres
    """
1029 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
1030 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
1031 60 storres
    intervalSa = \
1032 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1033 60 storres
    centerSa = \
1034 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1035 60 storres
    errorSa = \
1036 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1037 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1038 83 storres
    # End slz_interval_and_polynomial_to_sage
1039 62 storres
1040 172 storres
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None,
1041 172 storres
            targetPlusOnePrecRF = None, quasiExactRF = None):
1042 172 storres
    """
1043 172 storres
      Check if an element (argument) of the domain of function (function)
1044 172 storres
      yields a HTRN case (rounding to next) for the target precision
1045 172 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuraty).
1046 172 storres
    """
1047 172 storres
    ## Arguments filtering. TODO: filter the first argument for consistence.
1048 172 storres
    ## If no target accuracy is given, assume it is that of the argument.
1049 172 storres
    if targetRF is None:
1050 172 storres
        targetRF = argument.parent()
1051 172 storres
    ## Ditto for the real field holding the midpoints.
1052 172 storres
    if targetPlusOnePrecRF is None:
1053 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1054 172 storres
    ## Create a high accuracy RealField
1055 172 storres
    if quasiExactRF is None:
1056 172 storres
        quasiExactRF = RealField(1536)
1057 172 storres
1058 172 storres
    exactArgument                 = quasiExactRF(argument)
1059 172 storres
    quasiExactValue               = function(exactArgument)
1060 172 storres
    roundedValue                  = targetRF(quasiExactValue)
1061 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1062 172 storres
    # Upper midpoint.
1063 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1064 172 storres
    # Lower midpoint.
1065 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1066 172 storres
    binade                        = slz_compute_binade(roundedValue)
1067 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1068 172 storres
    #print "Argument:", argument
1069 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1070 174 storres
    #print "Binade:", binade
1071 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1072 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
1073 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1074 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1075 172 storres
    #print "Upper midpoint:", \
1076 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1077 172 storres
    #print "Rounded value :", \
1078 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1079 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1080 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1081 172 storres
    #print "Lower midpoint:", \
1082 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1083 172 storres
    ## Begining of the general case : check with the midpoint with
1084 172 storres
    #  greatest absolute value.
1085 172 storres
    if quasiExactValue > 0:
1086 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1087 172 storres
           binadeCorrectedTargetAccuracy:
1088 172 storres
            #print "Too close to the upper midpoint: ", \
1089 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1090 172 storres
            #print argument.n().str(base=16, \
1091 172 storres
            #  no_sci=False)
1092 172 storres
            #print "Lower midpoint:", \
1093 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1094 172 storres
            #print "Value         :", \
1095 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1096 172 storres
            #print "Upper midpoint:", \
1097 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1098 172 storres
            #print
1099 172 storres
            return True
1100 172 storres
    else:
1101 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1102 172 storres
           binadeCorrectedTargetAccuracy:
1103 172 storres
            #print "Too close to the upper midpoint: ", \
1104 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1105 172 storres
            #print argument.n().str(base=16, \
1106 172 storres
            #  no_sci=False)
1107 172 storres
            #print "Lower midpoint:", \
1108 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1109 172 storres
            #print "Value         :", \
1110 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1111 172 storres
            #print "Upper midpoint:", \
1112 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1113 172 storres
            #print
1114 172 storres
            return True
1115 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1116 172 storres
    ## For the midpoint of smaller absolute value,
1117 172 storres
    #  split cases with the powers of 2.
1118 172 storres
    if sno_abs_is_power_of_two(roundedValue):
1119 172 storres
        if quasiExactValue > 0:
1120 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1121 172 storres
               binadeCorrectedTargetAccuracy / 2:
1122 172 storres
                #print "Lower midpoint:", \
1123 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1124 172 storres
                #print "Value         :", \
1125 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1126 172 storres
                #print "Upper midpoint:", \
1127 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1128 172 storres
                #print
1129 172 storres
                return True
1130 172 storres
        else:
1131 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1132 172 storres
              binadeCorrectedTargetAccuracy / 2:
1133 172 storres
                #print "Lower midpoint:", \
1134 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1135 172 storres
                #print "Value         :",
1136 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1137 172 storres
                #print "Upper midpoint:",
1138 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1139 172 storres
                #print
1140 172 storres
                return True
1141 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1142 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
1143 172 storres
          #  smaller absolute value.
1144 172 storres
        if quasiExactValue > 0:
1145 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1146 172 storres
              binadeCorrectedTargetAccuracy:
1147 172 storres
                #print "Lower midpoint:", \
1148 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1149 172 storres
                #print "Value         :", \
1150 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1151 172 storres
                #print "Upper midpoint:", \
1152 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1153 172 storres
                #print
1154 172 storres
                return True
1155 172 storres
        else: # quasiExactValue <= 0
1156 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1157 172 storres
              binadeCorrectedTargetAccuracy:
1158 172 storres
                #print "Lower midpoint:", \
1159 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1160 172 storres
                #print "Value         :", \
1161 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1162 172 storres
                #print "Upper midpoint:", \
1163 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1164 172 storres
                #print
1165 172 storres
                return True
1166 172 storres
    #print "distance to the upper midpoint:", \
1167 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1168 172 storres
    #print "distance to the lower midpoint:", \
1169 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1170 172 storres
    return False
1171 172 storres
# End slz_is_htrn
1172 172 storres
1173 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
1174 80 storres
                                                precision,
1175 80 storres
                                                targetHardnessToRound,
1176 80 storres
                                                variable1,
1177 80 storres
                                                variable2):
1178 80 storres
    """
1179 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
1180 90 storres
     with the Coppersmith method.
1181 80 storres
    A the same time it computes :
1182 80 storres
    - 2^K (N);
1183 90 storres
    - 2^k (bound on the second variable)
1184 80 storres
    - lcm
1185 90 storres
1186 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1187 90 storres
                         variables.
1188 90 storres
    :param precision: the precision of the floating-point coefficients.
1189 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
1190 90 storres
    :param variable1: the first variable of the polynomial (an expression).
1191 90 storres
    :param variable2: the second variable of the polynomial (an expression).
1192 90 storres
1193 90 storres
    :returns: a 4 elements tuple:
1194 90 storres
                - the polynomial;
1195 91 storres
                - the modulus (N);
1196 91 storres
                - the t bound;
1197 90 storres
                - the lcm used to compute the integral coefficients and the
1198 90 storres
                  module.
1199 80 storres
    """
1200 80 storres
    # Create a new integer polynomial ring.
1201 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1202 80 storres
    # Coefficients are issued in the increasing power order.
1203 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1204 91 storres
    # Print the reversed list for debugging.
1205 170 storres
    print
1206 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1207 94 storres
    # Build the list of number we compute the lcm of.
1208 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1209 170 storres
    print "Coefficient denominators:", coefficientDenominators
1210 80 storres
    coefficientDenominators.append(2^precision)
1211 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
1212 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
1213 80 storres
    # Compute the expression corresponding to the new polynomial
1214 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1215 91 storres
    #print coefficientNumerators
1216 80 storres
    polynomialExpression = 0
1217 80 storres
    power = 0
1218 170 storres
    # Iterate over two lists at the same time, stop when the shorter
1219 170 storres
    # (is this case coefficientsNumerators) is
1220 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
1221 170 storres
    # of variable1.
1222 80 storres
    for numerator, denominator in \
1223 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
1224 80 storres
        multiplicator = leastCommonMultiple / denominator
1225 80 storres
        newCoefficient = numerator * multiplicator
1226 80 storres
        polynomialExpression += newCoefficient * variable1^power
1227 80 storres
        power +=1
1228 80 storres
    polynomialExpression += - variable2
1229 80 storres
    return (IP(polynomialExpression),
1230 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
1231 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1232 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1233 91 storres
            leastCommonMultiple) # If we want to make test computations.
1234 80 storres
1235 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1236 79 storres
1237 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
1238 79 storres
                                          precision):
1239 79 storres
    """
1240 79 storres
    Makes a variable substitution into the input polynomial so that the output
1241 79 storres
    polynomial can take integer arguments.
1242 79 storres
    All variables of the input polynomial "have precision p". That is to say
1243 103 storres
    that they are rationals with denominator == 2^(precision - 1):
1244 103 storres
    x = y/2^(precision - 1).
1245 79 storres
    We "incorporate" these denominators into the coefficients with,
1246 79 storres
    respectively, the "right" power.
1247 79 storres
    """
1248 79 storres
    polynomialField = ratPolyOfRat.parent()
1249 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
1250 91 storres
    #print "The polynomial field is:", polynomialField
1251 79 storres
    return \
1252 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1253 79 storres
                                   polynomialVariable/2^(precision-1)}))
1254 79 storres
1255 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1256 79 storres
1257 115 storres
1258 87 storres
print "\t...sageSLZ loaded"