Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (63,37 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 181 storres
        print "++Approximation error:", maxErrorSa.n()
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 181 storres
        # Very empirical shrinking factor.
434 176 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxPrecSa).log2().abs()
435 181 storres
        print "Shrink factor:", \
436 181 storres
              shrinkFactorSa.n(), \
437 181 storres
              intervalShrinkConstFactorSa
438 182 storres
        print
439 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
440 61 storres
        #print "Error ratio: ", errorRatioSa
441 181 storres
        # Make sure interval shrinks.
442 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
443 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
444 81 storres
            #print "Fixed"
445 61 storres
        else:
446 81 storres
            actualShrinkFactorSa = shrinkFactorSa
447 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
448 81 storres
            #print shrinkFactorSa, maxErrorSa
449 101 storres
        #print "Shrink factor", actualShrinkFactorSa
450 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
451 181 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
452 181 storres
                                actualShrinkFactorSa
453 71 storres
        #print "Current upper bound:", currentUpperBoundSa
454 61 storres
        sollya_lib_clear_obj(currentRangeSo)
455 181 storres
        # Check what is left with the bounds.
456 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
457 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
458 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
459 86 storres
            print "Can't find an interval."
460 86 storres
            print "Use either or both a higher polynomial degree or a higher",
461 86 storres
            print "internal precision."
462 86 storres
            print "Aborting!"
463 86 storres
            return (None, None, None, None)
464 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
465 61 storres
                                                      currentUpperBoundSa)
466 86 storres
        # print "New interval:",
467 86 storres
        # pobyso_autoprint(currentRangeSo)
468 120 storres
        #print "Second Taylor expansion call."
469 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
470 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
471 61 storres
                                                        currentRangeSo,
472 61 storres
                                                        absoluteErrorTypeSo)
473 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
474 85 storres
        #print "Max errorSo:",
475 85 storres
        #pobyso_autoprint(maxErrorSo)
476 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
477 85 storres
        #print "Max errorSa:", maxErrorSa
478 85 storres
        #print "Sollya prec:",
479 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
480 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
481 176 storres
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
482 81 storres
# End slz_compute_polynomial_and_interval
483 61 storres
484 122 storres
def slz_compute_reduced_polynomial(matrixRow,
485 98 storres
                                    knownMonomials,
486 106 storres
                                    var1,
487 98 storres
                                    var1Bound,
488 106 storres
                                    var2,
489 99 storres
                                    var2Bound):
490 98 storres
    """
491 125 storres
    Compute a polynomial from a single reduced matrix row.
492 122 storres
    This function was introduced in order to avoid the computation of the
493 125 storres
    all the polynomials  from the full matrix (even those built from rows
494 125 storres
    that do no verify the Coppersmith condition) as this may involves
495 152 storres
    expensive operations over (large) integers.
496 122 storres
    """
497 122 storres
    ## Check arguments.
498 122 storres
    if len(knownMonomials) == 0:
499 122 storres
        return None
500 122 storres
    # varNounds can be zero since 0^0 returns 1.
501 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
502 122 storres
        return None
503 122 storres
    ## Initialisations.
504 122 storres
    polynomialRing = knownMonomials[0].parent()
505 122 storres
    currentPolynomial = polynomialRing(0)
506 123 storres
    # TODO: use zip instead of indices.
507 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
508 122 storres
        currentCoefficient = matrixRow[colIndex]
509 122 storres
        if currentCoefficient != 0:
510 122 storres
            #print "Current coefficient:", currentCoefficient
511 122 storres
            currentMonomial = knownMonomials[colIndex]
512 122 storres
            #print "Monomial as multivariate polynomial:", \
513 122 storres
            #currentMonomial, type(currentMonomial)
514 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
515 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
516 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
517 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
518 122 storres
            if degreeInVar1 > 0:
519 122 storres
                currentCoefficient = \
520 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
521 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
522 122 storres
                #print "Current coefficient(1)", currentCoefficient
523 122 storres
            if degreeInVar2 > 0:
524 122 storres
                currentCoefficient = \
525 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
526 122 storres
                #print "Current coefficient(2)", currentCoefficient
527 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
528 122 storres
            #                                    currentMonomial)
529 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
530 122 storres
            #print "Current polynomial:", currentPolynomial
531 122 storres
        # End if
532 122 storres
    # End for colIndex.
533 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
534 122 storres
    return(currentPolynomial)
535 122 storres
# End slz_compute_reduced_polynomial
536 122 storres
#
537 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
538 122 storres
                                        knownMonomials,
539 122 storres
                                        var1,
540 122 storres
                                        var1Bound,
541 122 storres
                                        var2,
542 122 storres
                                        var2Bound):
543 122 storres
    """
544 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
545 122 storres
    """
546 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
547 122 storres
                                                knownMonomials,
548 122 storres
                                                var1,
549 122 storres
                                                var1Bound,
550 122 storres
                                                var2,
551 122 storres
                                                var2Bound)
552 122 storres
    )
553 177 storres
#
554 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
555 152 storres
                                         knownMonomials,
556 152 storres
                                         var1,
557 152 storres
                                         var1Bound,
558 152 storres
                                         var2,
559 152 storres
                                         var2Bound):
560 122 storres
    """
561 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
562 98 storres
    from the bounds of each variable, compute the corresponding polynomials
563 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
564 99 storres
565 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
566 172 storres
    They set the polynomial type of the output polynomials in list.
567 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
568 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
569 152 storres
                           build the polynomials;
570 152 storres
    @param var1:           the first variable (of the "right" type);
571 152 storres
    @param var1Bound:      the first variable bound;
572 152 storres
    @param var2:           the second variable (of the "right" type);
573 152 storres
    @param var2Bound:      the second variable bound.
574 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
575 152 storres
             and scaled down with the bounds
576 98 storres
    """
577 99 storres
578 98 storres
    # TODO: check input arguments.
579 98 storres
    reducedPolynomials = []
580 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
581 98 storres
    for matrixRow in reducedMatrix.rows():
582 102 storres
        currentPolynomial = 0
583 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
584 98 storres
            currentCoefficient = matrixRow[colIndex]
585 106 storres
            if currentCoefficient != 0:
586 106 storres
                #print "Current coefficient:", currentCoefficient
587 106 storres
                currentMonomial = knownMonomials[colIndex]
588 106 storres
                parentRing = currentMonomial.parent()
589 106 storres
                #print "Monomial as multivariate polynomial:", \
590 106 storres
                #currentMonomial, type(currentMonomial)
591 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
592 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
593 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
594 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
595 106 storres
                if degreeInVar1 > 0:
596 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
597 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
598 106 storres
                    #print "Current coefficient(1)", currentCoefficient
599 106 storres
                if degreeInVar2 > 0:
600 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
601 106 storres
                    #print "Current coefficient(2)", currentCoefficient
602 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
603 106 storres
                #                                    currentMonomial)
604 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
605 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
606 168 storres
                    #print "!!!! constant term !!!!"
607 106 storres
                #print "Current polynomial:", currentPolynomial
608 106 storres
            # End if
609 106 storres
        # End for colIndex.
610 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
611 99 storres
        reducedPolynomials.append(currentPolynomial)
612 98 storres
    return reducedPolynomials
613 177 storres
# End slz_compute_reduced_polynomials_list.
614 98 storres
615 177 storres
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
616 177 storres
                                                   knownMonomials,
617 177 storres
                                                   var1,
618 177 storres
                                                   var1Bound,
619 177 storres
                                                   var2,
620 177 storres
                                                   var2Bound):
621 177 storres
    """
622 177 storres
    From a list of rows, holding the coefficients, from a monomials list,
623 177 storres
    from the bounds of each variable, compute the corresponding polynomials
624 177 storres
    scaled back by dividing by the "right" powers of the variables bounds.
625 177 storres
626 177 storres
    The elements in knownMonomials must be of the "right" polynomial type.
627 177 storres
    They set the polynomial type of the output polynomials in list.
628 177 storres
    @param rowsList:       the reduced matrix as output from LLL;
629 177 storres
    @param kwnonMonomials: the ordered list of the monomials used to
630 177 storres
                           build the polynomials;
631 177 storres
    @param var1:           the first variable (of the "right" type);
632 177 storres
    @param var1Bound:      the first variable bound;
633 177 storres
    @param var2:           the second variable (of the "right" type);
634 177 storres
    @param var2Bound:      the second variable bound.
635 177 storres
    @return: a list of polynomials obtained with the reduced coefficients
636 177 storres
             and scaled down with the bounds
637 177 storres
    """
638 177 storres
639 177 storres
    # TODO: check input arguments.
640 177 storres
    reducedPolynomials = []
641 177 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
642 177 storres
    for matrixRow in rowsList:
643 177 storres
        currentPolynomial = 0
644 177 storres
        for colIndex in xrange(0, len(knownMonomials)):
645 177 storres
            currentCoefficient = matrixRow[colIndex]
646 177 storres
            if currentCoefficient != 0:
647 177 storres
                #print "Current coefficient:", currentCoefficient
648 177 storres
                currentMonomial = knownMonomials[colIndex]
649 177 storres
                parentRing = currentMonomial.parent()
650 177 storres
                #print "Monomial as multivariate polynomial:", \
651 177 storres
                #currentMonomial, type(currentMonomial)
652 177 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
653 177 storres
                #print "Degree in var", var1, ":", degreeInVar1
654 177 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
655 177 storres
                #print "Degree in var", var2, ":", degreeInVar2
656 177 storres
                if degreeInVar1 > 0:
657 177 storres
                    currentCoefficient /= var1Bound^degreeInVar1
658 177 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
659 177 storres
                    #print "Current coefficient(1)", currentCoefficient
660 177 storres
                if degreeInVar2 > 0:
661 177 storres
                    currentCoefficient /= var2Bound^degreeInVar2
662 177 storres
                    #print "Current coefficient(2)", currentCoefficient
663 177 storres
                #print "Current reduced monomial:", (currentCoefficient * \
664 177 storres
                #                                    currentMonomial)
665 177 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
666 177 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
667 177 storres
                    #print "!!!! constant term !!!!"
668 177 storres
                #print "Current polynomial:", currentPolynomial
669 177 storres
            # End if
670 177 storres
        # End for colIndex.
671 177 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
672 177 storres
        reducedPolynomials.append(currentPolynomial)
673 177 storres
    return reducedPolynomials
674 177 storres
# End slz_compute_reduced_polynomials_list_from_rows.
675 177 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 177 storres
    ## The variable can be called anything.
692 80 storres
    x = functionSa.variables()[0]
693 72 storres
    # Scalling the domain -> [1,2[.
694 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
695 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
696 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
697 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
698 156 storres
    if debug:
699 156 storres
        print "domainScalingExpression for argument :", \
700 156 storres
        invDomainScalingExpressionSa
701 190 storres
        print "function: ", functionSa
702 190 storres
    ff = functionSa.subs({x : domainScalingExpressionSa})
703 190 storres
    ## Bless expression as a function.
704 190 storres
    ff = ff.function(x)
705 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
706 177 storres
    #domainScalingFunction(x) = invDomainScalingExpressionSa
707 177 storres
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
708 151 storres
    scaledLowerBoundSa = \
709 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
710 151 storres
    scaledUpperBoundSa = \
711 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
712 156 storres
    if debug:
713 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
714 156 storres
              scaledUpperBoundSa
715 72 storres
    #
716 72 storres
    # Scalling the image -> [1,2[.
717 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
718 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
719 72 storres
    if flbSa <= fubSa: # Increasing
720 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
721 72 storres
    else: # Decreasing
722 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
723 156 storres
    if debug:
724 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
725 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
726 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
727 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
728 156 storres
    if debug:
729 156 storres
        print "imageScalingExpression for argument :", \
730 156 storres
              invImageScalingExpressionSa
731 72 storres
    iis = invImageScalingExpressionSa.function(x)
732 72 storres
    fff = iis.subs({x:ff})
733 156 storres
    if debug:
734 156 storres
        print "fff:", fff,
735 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
736 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
737 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
738 151 storres
# End slz_compute_scaled_function
739 72 storres
740 179 storres
def slz_fix_bounds_for_binades(lowerBound,
741 179 storres
                               upperBound,
742 190 storres
                               func = None,
743 179 storres
                               domainDirection = -1,
744 179 storres
                               imageDirection  = -1):
745 179 storres
    """
746 179 storres
    Assuming the function is increasing or decreasing over the
747 179 storres
    [lowerBound, upperBound] interval, return a lower bound lb and
748 179 storres
    an upper bound ub such that:
749 179 storres
    - lb and ub belong to the same binade;
750 179 storres
    - func(lb) and func(ub) belong to the same binade.
751 179 storres
    domainDirection indicate how bounds move to fit into the same binade:
752 179 storres
    - a negative value move the upper bound down;
753 179 storres
    - a positive value move the lower bound up.
754 179 storres
    imageDirection indicate how bounds move in order to have their image
755 179 storres
    fit into the same binade, variation of the function is also condidered.
756 179 storres
    For an increasing function:
757 179 storres
    - negative value moves the upper bound down (and its image value as well);
758 179 storres
    - a positive values moves the lower bound up (and its image value as well);
759 179 storres
    For a decreasing function it is the other way round.
760 179 storres
    """
761 179 storres
    ## Arguments check
762 179 storres
    if lowerBound > upperBound:
763 179 storres
        return None
764 190 storres
    if lowerBound == upperBound:
765 190 storres
        return (lowerBound, upperBound)
766 179 storres
    if func is None:
767 179 storres
        return None
768 179 storres
    #
769 179 storres
    #varFunc = func.variables()[0]
770 179 storres
    lb = lowerBound
771 179 storres
    ub = upperBound
772 179 storres
    lbBinade = slz_compute_binade(lb)
773 179 storres
    ubBinade = slz_compute_binade(ub)
774 179 storres
    ## Domain binade.
775 179 storres
    while lbBinade != ubBinade:
776 179 storres
        newIntervalWidth = (ub - lb) / 2
777 179 storres
        if domainDirection < 0:
778 179 storres
            ub = lb + newIntervalWidth
779 179 storres
            ubBinade = slz_compute_binade(ub)
780 179 storres
        else:
781 179 storres
            lb = lb + newIntervalWidth
782 179 storres
            lbBinade = slz_compute_binade(lb)
783 179 storres
    ## Image binade.
784 179 storres
    if lb == ub:
785 179 storres
        return (lb, ub)
786 179 storres
    lbImg = func(lb)
787 179 storres
    ubImg = func(ub)
788 179 storres
    funcIsInc = (ubImg >= lbImg)
789 179 storres
    lbImgBinade = slz_compute_binade(lbImg)
790 179 storres
    ubImgBinade = slz_compute_binade(ubImg)
791 179 storres
    while lbImgBinade != ubImgBinade:
792 179 storres
        newIntervalWidth = (ub - lb) / 2
793 179 storres
        if imageDirection < 0:
794 179 storres
            if funcIsInc:
795 179 storres
                ub = lb + newIntervalWidth
796 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
797 179 storres
                #print ubImgBinade
798 179 storres
            else:
799 179 storres
                lb = lb + newIntervalWidth
800 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
801 179 storres
                #print lbImgBinade
802 179 storres
        else:
803 179 storres
            if funcIsInc:
804 179 storres
                lb = lb + newIntervalWidth
805 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
806 179 storres
                #print lbImgBinade
807 179 storres
            else:
808 179 storres
                ub = lb + newIntervalWidth
809 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
810 179 storres
                #print ubImgBinade
811 179 storres
    # End while lbImgBinade != ubImgBinade:
812 179 storres
    return (lb, ub)
813 179 storres
# End slz_fix_bounds_for_binades.
814 179 storres
815 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
816 79 storres
    # Create a polynomial over the rationals.
817 179 storres
    ratPolynomialRing = QQ[str(polyOfFloat.variables()[0])]
818 179 storres
    return(ratPolynomialRing(polyOfFloat))
819 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
820 81 storres
821 188 storres
def slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(polyOfFloat):
822 188 storres
    """
823 188 storres
     Create a polynomial over the rationals where all denominators are
824 188 storres
     powers of two.
825 188 storres
    """
826 188 storres
    polyVariable = polyOfFloat.variables()[0]
827 188 storres
    RPR = QQ[str(polyVariable)]
828 188 storres
    polyCoeffs      = polyOfFloat.coefficients()
829 188 storres
    #print polyCoeffs
830 188 storres
    polyExponents   = polyOfFloat.exponents()
831 188 storres
    #print polyExponents
832 188 storres
    polyDenomPtwoCoeffs = []
833 188 storres
    for coeff in polyCoeffs:
834 188 storres
        polyDenomPtwoCoeffs.append(sno_float_to_rat_pow_of_two_denom(coeff))
835 188 storres
        #print "Converted coefficient:", sno_float_to_rat_pow_of_two_denom(coeff),
836 188 storres
        #print type(sno_float_to_rat_pow_of_two_denom(coeff))
837 188 storres
    ratPoly = RPR(0)
838 188 storres
    #print type(ratPoly)
839 188 storres
    ## !!! CAUTION !!! Do not use the RPR(coeff * polyVariagle^exponent)
840 188 storres
    #  The coefficient becomes plainly wrong when exponent == 0.
841 188 storres
    #  No clue as to why.
842 188 storres
    for coeff, exponent in zip(polyDenomPtwoCoeffs, polyExponents):
843 188 storres
        ratPoly += coeff * RPR(polyVariable^exponent)
844 188 storres
    return ratPoly
845 188 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
846 188 storres
847 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
848 63 storres
                                      lowerBoundSa,
849 60 storres
                                      upperBoundSa, floatingPointPrecSa,
850 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
851 60 storres
    """
852 60 storres
    Under the assumption that:
853 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
854 60 storres
    - lowerBound and upperBound belong to the same binade.
855 60 storres
    from a:
856 60 storres
    - function;
857 60 storres
    - a degree
858 60 storres
    - a pair of bounds;
859 60 storres
    - the floating-point precision we work on;
860 60 storres
    - the internal Sollya precision;
861 64 storres
    - the requested approximation error
862 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
863 61 storres
    It return a list of tuples, each made of:
864 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
865 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
866 61 storres
    - the approximation interval;
867 72 storres
    - the center, x0, of the interval;
868 61 storres
    - the corresponding approximation error.
869 100 storres
    TODO: fix endless looping for some parameters sets.
870 60 storres
    """
871 120 storres
    resultArray = []
872 101 storres
    # Set Sollya to the necessary internal precision.
873 120 storres
    precChangedSa = False
874 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
875 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
876 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
877 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
878 120 storres
        precChangedSa = True
879 101 storres
    #
880 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
881 101 storres
    # Scaled function: [1=,2] -> [1,2].
882 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
883 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
884 115 storres
                slz_compute_scaled_function(functionSa,                       \
885 115 storres
                                            lowerBoundSa,                     \
886 115 storres
                                            upperBoundSa,                     \
887 80 storres
                                            floatingPointPrecSa)
888 166 storres
    # In case bounds were in the negative real one may need to
889 166 storres
    # switch scaled bounds.
890 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
891 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
892 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
893 166 storres
        #print "Switching!"
894 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
895 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
896 159 storres
    functionSo = \
897 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
898 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
899 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
900 61 storres
                                                  scaledUpperBoundSa)
901 176 storres
902 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
903 60 storres
                                              upperBoundSa.parent().precision()))
904 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
905 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
906 176 storres
    while True:
907 176 storres
        ## Compute the first Taylor expansion.
908 176 storres
        print "Computing a Taylor expansion..."
909 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
910 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
911 176 storres
                                        currentScaledLowerBoundSa,
912 176 storres
                                        currentScaledUpperBoundSa,
913 176 storres
                                        approxPrecSa, internalSollyaPrecSa)
914 176 storres
        print "...done."
915 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
916 176 storres
        #  This value goes to the first variable: polySo. Other variables are
917 176 storres
        #  not assigned and should not be tested.
918 176 storres
        if polySo is None:
919 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
920 176 storres
            if precChangedSa:
921 176 storres
                pobyso_set_prec_so_so(currentSollyaPrecSo)
922 176 storres
                sollya_lib_clear_obj(currentSollyaPrecSo)
923 176 storres
            sollya_lib_clear_obj(functionSo)
924 176 storres
            sollya_lib_clear_obj(degreeSo)
925 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
926 176 storres
            return None
927 176 storres
        ## Add to the result array.
928 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
929 176 storres
        changeVarExpressionSo = \
930 176 storres
            sollya_lib_build_function_sub( \
931 176 storres
                              sollya_lib_build_function_free_variable(),
932 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
933 176 storres
        polyVarChangedSo = \
934 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
935 176 storres
        #### Get rid of the variable change Sollya stuff.
936 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
937 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
938 101 storres
                            intervalCenterSo, maxErrorSo))
939 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
940 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
941 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
942 176 storres
        # If the error and interval are OK a the first try, just return.
943 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
944 176 storres
            (errorSa <= approxPrecSa):
945 176 storres
            if precChangedSa:
946 176 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
947 176 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
948 176 storres
            sollya_lib_clear_obj(functionSo)
949 176 storres
            sollya_lib_clear_obj(degreeSo)
950 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
951 101 storres
            #print "Approximation error:", errorSa
952 176 storres
            return resultArray
953 176 storres
        ## The returned interval upper bound does not reach the requested upper
954 176 storres
        #  upper bound: compute the next upper bound.
955 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
956 176 storres
        #  enlarge the interval
957 81 storres
        currentErrorRatio = approxPrecSa / errorSa
958 176 storres
        ## --|--------------------------------------------------------------|--
959 176 storres
        #  --|--------------------|--------------------------------------------
960 176 storres
        #  --|----------------------------|------------------------------------
961 176 storres
        ## Starting point for the next upper bound.
962 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
963 101 storres
        # Compute the increment.
964 176 storres
        newBoundsWidthSa = \
965 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
966 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
967 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
968 176 storres
        # Take into account the original interval upper bound.
969 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
970 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
971 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
972 85 storres
            print "Can't shrink the interval anymore!"
973 85 storres
            print "You should consider increasing the Sollya internal precision"
974 85 storres
            print "or the polynomial degree."
975 85 storres
            print "Giving up!"
976 176 storres
            if precChangedSa:
977 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
978 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
979 85 storres
            sollya_lib_clear_obj(functionSo)
980 85 storres
            sollya_lib_clear_obj(degreeSo)
981 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
982 85 storres
            return None
983 176 storres
        # Compute the other expansions.
984 176 storres
        # Test for insufficient precision.
985 81 storres
# End slz_get_intervals_and_polynomials
986 60 storres
987 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
988 61 storres
    """
989 151 storres
    Compute the scaling expression to map an interval that spans at most
990 166 storres
    a single binade into [1, 2) and the inverse expression as well.
991 165 storres
    If the interval spans more than one binade, result is wrong since
992 165 storres
    scaling is only based on the lower bound.
993 62 storres
    Not very sure that the transformation makes sense for negative numbers.
994 61 storres
    """
995 165 storres
    # The "one of the bounds is 0" special case. Here we consider
996 165 storres
    # the interval as the subnormals binade.
997 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
998 165 storres
        # The upper bound is (or should be) positive.
999 165 storres
        if boundsInterval.endpoints()[0] == 0:
1000 165 storres
            if boundsInterval.endpoints()[1] == 0:
1001 165 storres
                return None
1002 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
1003 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
1004 165 storres
            # The upper bound is a power of two
1005 165 storres
            if binade == l2:
1006 165 storres
                scalingCoeff    = 2^(-binade)
1007 165 storres
                invScalingCoeff = 2^(binade)
1008 165 storres
                scalingOffset   = 1
1009 179 storres
                return \
1010 179 storres
                  ((scalingCoeff * expVar + scalingOffset).function(expVar),
1011 179 storres
                  ((expVar - scalingOffset) * invScalingCoeff).function(expVar))
1012 165 storres
            else:
1013 165 storres
                scalingCoeff    = 2^(-binade-1)
1014 165 storres
                invScalingCoeff = 2^(binade+1)
1015 165 storres
                scalingOffset   = 1
1016 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1017 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1018 165 storres
        # The lower bound is (or should be) negative.
1019 165 storres
        if boundsInterval.endpoints()[1] == 0:
1020 165 storres
            if boundsInterval.endpoints()[0] == 0:
1021 165 storres
                return None
1022 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
1023 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
1024 165 storres
            # The upper bound is a power of two
1025 165 storres
            if binade == l2:
1026 165 storres
                scalingCoeff    = -2^(-binade)
1027 165 storres
                invScalingCoeff = -2^(binade)
1028 165 storres
                scalingOffset   = 1
1029 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1030 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1031 165 storres
            else:
1032 165 storres
                scalingCoeff    = -2^(-binade-1)
1033 165 storres
                invScalingCoeff = -2^(binade+1)
1034 165 storres
                scalingOffset   = 1
1035 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1036 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
1037 165 storres
    # General case
1038 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
1039 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
1040 165 storres
    # We allow for a single exception in binade spanning is when the
1041 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
1042 165 storres
    # "inner bound" + 1.
1043 165 storres
    if boundsInterval.endpoints()[0] > 0:
1044 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
1045 165 storres
        if lbBinade != ubBinade:
1046 165 storres
            print "Different binades."
1047 165 storres
            if ubL2 != ubBinade:
1048 165 storres
                print "Not a power of 2."
1049 165 storres
                return None
1050 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1051 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1052 165 storres
                return None
1053 165 storres
    else:
1054 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
1055 165 storres
        if lbBinade != ubBinade:
1056 165 storres
            print "Different binades."
1057 165 storres
            if lbL2 != lbBinade:
1058 165 storres
                print "Not a power of 2."
1059 165 storres
                return None
1060 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1061 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1062 165 storres
                return None
1063 165 storres
    #print "Lower bound binade:", binade
1064 165 storres
    if boundsInterval.endpoints()[0] > 0:
1065 179 storres
        return \
1066 179 storres
            ((2^(-lbBinade) * expVar).function(expVar),
1067 179 storres
             (2^(lbBinade) * expVar).function(expVar))
1068 165 storres
    else:
1069 179 storres
        return \
1070 179 storres
            ((-(2^(-ubBinade)) * expVar).function(expVar),
1071 179 storres
             (-(2^(ubBinade)) * expVar).function(expVar))
1072 165 storres
"""
1073 165 storres
    # Code sent to attic. Should be the base for a
1074 165 storres
    # "slz_interval_translate_expression" rather than scale.
1075 165 storres
    # Extra control and special cases code  added in
1076 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
1077 165 storres
    # this new function.
1078 62 storres
    # The scaling offset is only used for negative numbers.
1079 151 storres
    # When the absolute value of the lower bound is < 0.
1080 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
1081 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1082 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1083 62 storres
            invScalingCoeff = 1/scalingCoeff
1084 80 storres
            return((scalingCoeff * expVar,
1085 80 storres
                    invScalingCoeff * expVar))
1086 60 storres
        else:
1087 62 storres
            scalingCoeff = \
1088 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
1089 62 storres
            scalingOffset = -3 * scalingCoeff
1090 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1091 80 storres
                    1/scalingCoeff * expVar + 3))
1092 61 storres
    else:
1093 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1094 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1095 61 storres
            scalingOffset = 0
1096 80 storres
            return((scalingCoeff * expVar,
1097 80 storres
                    1/scalingCoeff * expVar))
1098 61 storres
        else:
1099 62 storres
            scalingCoeff = \
1100 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1101 62 storres
            scalingOffset =  -3 * scalingCoeff
1102 62 storres
            #scalingOffset = 0
1103 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1104 80 storres
                    1/scalingCoeff * expVar + 3))
1105 165 storres
"""
1106 151 storres
# End slz_interval_scaling_expression
1107 61 storres
1108 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1109 72 storres
    """
1110 72 storres
    Compute the Sage version of the Taylor polynomial and it's
1111 72 storres
    companion data (interval, center...)
1112 72 storres
    The input parameter is a five elements tuple:
1113 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1114 79 storres
           real ring;
1115 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1116 79 storres
           over a real ring;
1117 72 storres
    - [2]: the interval (as Sollya range);
1118 72 storres
    - [3]: the interval center;
1119 72 storres
    - [4]: the approximation error.
1120 72 storres
1121 72 storres
    The function return a 5 elements tuple: formed with all the
1122 72 storres
    input elements converted into their Sollya counterpart.
1123 72 storres
    """
1124 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
1125 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
1126 60 storres
    intervalSa = \
1127 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1128 60 storres
    centerSa = \
1129 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1130 60 storres
    errorSa = \
1131 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1132 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1133 83 storres
    # End slz_interval_and_polynomial_to_sage
1134 62 storres
1135 172 storres
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None,
1136 172 storres
            targetPlusOnePrecRF = None, quasiExactRF = None):
1137 172 storres
    """
1138 172 storres
      Check if an element (argument) of the domain of function (function)
1139 172 storres
      yields a HTRN case (rounding to next) for the target precision
1140 183 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuracy).
1141 172 storres
    """
1142 183 storres
    ## Arguments filtering.
1143 183 storres
    ## TODO: filter the first argument for consistence.
1144 172 storres
    if targetRF is None:
1145 172 storres
        targetRF = argument.parent()
1146 172 storres
    ## Ditto for the real field holding the midpoints.
1147 172 storres
    if targetPlusOnePrecRF is None:
1148 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1149 183 storres
    ## If no quasiExactField is provided, create a high accuracy RealField.
1150 172 storres
    if quasiExactRF is None:
1151 172 storres
        quasiExactRF = RealField(1536)
1152 195 storres
    function                      = function.function(function.variables()[0])
1153 172 storres
    exactArgument                 = quasiExactRF(argument)
1154 172 storres
    quasiExactValue               = function(exactArgument)
1155 172 storres
    roundedValue                  = targetRF(quasiExactValue)
1156 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1157 172 storres
    # Upper midpoint.
1158 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1159 172 storres
    # Lower midpoint.
1160 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1161 172 storres
    binade                        = slz_compute_binade(roundedValue)
1162 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1163 172 storres
    #print "Argument:", argument
1164 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1165 174 storres
    #print "Binade:", binade
1166 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1167 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
1168 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1169 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1170 172 storres
    #print "Upper midpoint:", \
1171 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1172 172 storres
    #print "Rounded value :", \
1173 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1174 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1175 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1176 172 storres
    #print "Lower midpoint:", \
1177 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1178 172 storres
    ## Begining of the general case : check with the midpoint with
1179 172 storres
    #  greatest absolute value.
1180 172 storres
    if quasiExactValue > 0:
1181 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1182 172 storres
           binadeCorrectedTargetAccuracy:
1183 183 storres
            #print "Too close to the upper midpoint: ", \
1184 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1185 172 storres
            #print argument.n().str(base=16, \
1186 172 storres
            #  no_sci=False)
1187 172 storres
            #print "Lower midpoint:", \
1188 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1189 172 storres
            #print "Value         :", \
1190 183 storres
            # quasiExactValue.n(prec=200).str(base=2)
1191 172 storres
            #print "Upper midpoint:", \
1192 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1193 172 storres
            return True
1194 172 storres
    else:
1195 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1196 172 storres
           binadeCorrectedTargetAccuracy:
1197 172 storres
            #print "Too close to the upper midpoint: ", \
1198 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1199 172 storres
            #print argument.n().str(base=16, \
1200 172 storres
            #  no_sci=False)
1201 172 storres
            #print "Lower midpoint:", \
1202 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1203 172 storres
            #print "Value         :", \
1204 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1205 172 storres
            #print "Upper midpoint:", \
1206 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1207 172 storres
            #print
1208 172 storres
            return True
1209 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1210 172 storres
    ## For the midpoint of smaller absolute value,
1211 172 storres
    #  split cases with the powers of 2.
1212 172 storres
    if sno_abs_is_power_of_two(roundedValue):
1213 172 storres
        if quasiExactValue > 0:
1214 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1215 172 storres
               binadeCorrectedTargetAccuracy / 2:
1216 172 storres
                #print "Lower midpoint:", \
1217 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1218 172 storres
                #print "Value         :", \
1219 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1220 172 storres
                #print "Upper midpoint:", \
1221 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1222 172 storres
                #print
1223 172 storres
                return True
1224 172 storres
        else:
1225 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1226 172 storres
              binadeCorrectedTargetAccuracy / 2:
1227 172 storres
                #print "Lower midpoint:", \
1228 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1229 172 storres
                #print "Value         :",
1230 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1231 172 storres
                #print "Upper midpoint:",
1232 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1233 172 storres
                #print
1234 172 storres
                return True
1235 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1236 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
1237 172 storres
          #  smaller absolute value.
1238 172 storres
        if quasiExactValue > 0:
1239 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1240 172 storres
              binadeCorrectedTargetAccuracy:
1241 172 storres
                #print "Lower midpoint:", \
1242 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1243 172 storres
                #print "Value         :", \
1244 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1245 172 storres
                #print "Upper midpoint:", \
1246 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1247 172 storres
                #print
1248 172 storres
                return True
1249 172 storres
        else: # quasiExactValue <= 0
1250 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1251 172 storres
              binadeCorrectedTargetAccuracy:
1252 172 storres
                #print "Lower midpoint:", \
1253 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1254 172 storres
                #print "Value         :", \
1255 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1256 172 storres
                #print "Upper midpoint:", \
1257 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1258 172 storres
                #print
1259 172 storres
                return True
1260 172 storres
    #print "distance to the upper midpoint:", \
1261 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1262 172 storres
    #print "distance to the lower midpoint:", \
1263 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1264 172 storres
    return False
1265 172 storres
# End slz_is_htrn
1266 172 storres
1267 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
1268 80 storres
                                                precision,
1269 80 storres
                                                targetHardnessToRound,
1270 80 storres
                                                variable1,
1271 80 storres
                                                variable2):
1272 80 storres
    """
1273 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
1274 90 storres
     with the Coppersmith method.
1275 80 storres
    A the same time it computes :
1276 80 storres
    - 2^K (N);
1277 90 storres
    - 2^k (bound on the second variable)
1278 80 storres
    - lcm
1279 90 storres
1280 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1281 90 storres
                         variables.
1282 90 storres
    :param precision: the precision of the floating-point coefficients.
1283 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
1284 90 storres
    :param variable1: the first variable of the polynomial (an expression).
1285 90 storres
    :param variable2: the second variable of the polynomial (an expression).
1286 90 storres
1287 90 storres
    :returns: a 4 elements tuple:
1288 90 storres
                - the polynomial;
1289 91 storres
                - the modulus (N);
1290 91 storres
                - the t bound;
1291 90 storres
                - the lcm used to compute the integral coefficients and the
1292 90 storres
                  module.
1293 80 storres
    """
1294 80 storres
    # Create a new integer polynomial ring.
1295 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1296 80 storres
    # Coefficients are issued in the increasing power order.
1297 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1298 91 storres
    # Print the reversed list for debugging.
1299 179 storres
    #print
1300 179 storres
    #print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1301 94 storres
    # Build the list of number we compute the lcm of.
1302 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1303 179 storres
    #print "Coefficient denominators:", coefficientDenominators
1304 80 storres
    coefficientDenominators.append(2^precision)
1305 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
1306 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
1307 80 storres
    # Compute the expression corresponding to the new polynomial
1308 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1309 91 storres
    #print coefficientNumerators
1310 80 storres
    polynomialExpression = 0
1311 80 storres
    power = 0
1312 170 storres
    # Iterate over two lists at the same time, stop when the shorter
1313 170 storres
    # (is this case coefficientsNumerators) is
1314 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
1315 170 storres
    # of variable1.
1316 80 storres
    for numerator, denominator in \
1317 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
1318 80 storres
        multiplicator = leastCommonMultiple / denominator
1319 80 storres
        newCoefficient = numerator * multiplicator
1320 80 storres
        polynomialExpression += newCoefficient * variable1^power
1321 80 storres
        power +=1
1322 80 storres
    polynomialExpression += - variable2
1323 80 storres
    return (IP(polynomialExpression),
1324 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
1325 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1326 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1327 91 storres
            leastCommonMultiple) # If we want to make test computations.
1328 80 storres
1329 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1330 79 storres
1331 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
1332 79 storres
                                          precision):
1333 79 storres
    """
1334 79 storres
    Makes a variable substitution into the input polynomial so that the output
1335 79 storres
    polynomial can take integer arguments.
1336 79 storres
    All variables of the input polynomial "have precision p". That is to say
1337 103 storres
    that they are rationals with denominator == 2^(precision - 1):
1338 103 storres
    x = y/2^(precision - 1).
1339 79 storres
    We "incorporate" these denominators into the coefficients with,
1340 79 storres
    respectively, the "right" power.
1341 79 storres
    """
1342 79 storres
    polynomialField = ratPolyOfRat.parent()
1343 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
1344 91 storres
    #print "The polynomial field is:", polynomialField
1345 79 storres
    return \
1346 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1347 79 storres
                                   polynomialVariable/2^(precision-1)}))
1348 79 storres
1349 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1350 79 storres
1351 177 storres
def slz_reduce_and_test_base(matrixToReduce,
1352 177 storres
                             nAtAlpha,
1353 177 storres
                             monomialsCountSqrt):
1354 177 storres
    """
1355 177 storres
    Reduces the basis, tests the Coppersmith condition and returns
1356 177 storres
    a list of rows that comply with the condition.
1357 177 storres
    """
1358 177 storres
    ccComplientRowsList = []
1359 177 storres
    reducedMatrix = matrixToReduce.LLL(None)
1360 177 storres
    if not reducedMatrix.is_LLL_reduced():
1361 177 storres
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
1362 177 storres
    else:
1363 177 storres
        print "reducedMatrix is actually reduced."
1364 177 storres
    print "N^alpha:", nAtAlpha.n()
1365 177 storres
    rowIndex = 0
1366 177 storres
    for row in reducedMatrix.rows():
1367 177 storres
        l2Norm = row.norm(2)
1368 177 storres
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
1369 177 storres
                monomialsCountSqrt.n(), ". Is vector OK?",
1370 177 storres
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
1371 177 storres
            ccComplientRowsList.append(row)
1372 177 storres
            print "True"
1373 177 storres
        else:
1374 177 storres
            print "False"
1375 177 storres
    # End for
1376 177 storres
    return ccComplientRowsList
1377 177 storres
# End slz_reduce_and_test_base
1378 115 storres
1379 177 storres
def slz_resultant_tuple(poly1, poly2, elimVar):
1380 179 storres
    """
1381 179 storres
    Compute the resultant for two polynomials for a given variable
1382 179 storres
    and return the (poly1, poly2, resultant) if the resultant
1383 180 storres
    is not 0.
1384 179 storres
    Return () otherwise.
1385 179 storres
    """
1386 181 storres
    polynomialRing0    = poly1.parent()
1387 177 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1388 180 storres
    if resultantInElimVar.is_zero():
1389 177 storres
        return ()
1390 177 storres
    else:
1391 177 storres
        return (poly1, poly2, resultantInElimVar)
1392 177 storres
# End slz_resultant_tuple.
1393 177 storres
#
1394 87 storres
print "\t...sageSLZ loaded"