Statistiques
| Révision :

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

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