Statistiques
| Révision :

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

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