Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (89,08 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 225 storres
import inspect
14 225 storres
#
15 165 storres
def slz_compute_binade(number):
16 165 storres
    """"
17 165 storres
    For a given number, compute the "binade" that is integer m such that
18 165 storres
    2^m <= number < 2^(m+1). If number == 0 return None.
19 165 storres
    """
20 165 storres
    # Checking the parameter.
21 172 storres
    # The exception construction is used to detect if number is a RealNumber
22 165 storres
    # since not all numbers have
23 165 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
24 165 storres
    try:
25 165 storres
        classTree = [number.__class__] + number.mro()
26 172 storres
        # If the number is not a RealNumber (or offspring thereof) try
27 165 storres
        # to transform it.
28 165 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
29 165 storres
            numberAsRR = RR(number)
30 165 storres
        else:
31 165 storres
            numberAsRR = number
32 165 storres
    except AttributeError:
33 165 storres
        return None
34 165 storres
    # Zero special case.
35 165 storres
    if numberAsRR == 0:
36 165 storres
        return RR(-infinity)
37 165 storres
    else:
38 176 storres
        realField           = numberAsRR.parent()
39 176 storres
        numberLog2          = numberAsRR.abs().log2()
40 176 storres
        floorNumberLog2     = floor(numberLog2)
41 176 storres
        ## Do not get caught by rounding of log2() both ways.
42 176 storres
        ## When numberLog2 is an integer, compare numberAsRR
43 176 storres
        #  with 2^numberLog2.
44 176 storres
        if floorNumberLog2 == numberLog2:
45 176 storres
            if numberAsRR.abs() < realField(2^floorNumberLog2):
46 176 storres
                return floorNumberLog2 - 1
47 176 storres
            else:
48 176 storres
                return floorNumberLog2
49 176 storres
        else:
50 176 storres
            return floorNumberLog2
51 165 storres
# End slz_compute_binade
52 165 storres
53 115 storres
#
54 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
55 119 storres
    """
56 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
57 121 storres
58 121 storres
    NOTE::
59 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
60 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
61 125 storres
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
62 125 storres
        this case from that of "really" invalid arguments.
63 121 storres
64 119 storres
    """
65 121 storres
    # Check the parameters.
66 125 storres
    # RealNumbers or RealNumber offspring only.
67 165 storres
    # The exception construction is necessary since not all objects have
68 125 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
69 124 storres
    try:
70 124 storres
        classTree = [number.__class__] + number.mro()
71 124 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
72 124 storres
            return None
73 124 storres
    except AttributeError:
74 121 storres
        return None
75 121 storres
    # Non zero negative integers only for emin.
76 121 storres
    if emin >= 0 or int(emin) != emin:
77 121 storres
        return None
78 121 storres
    # Non zero positive integers only for emax.
79 121 storres
    if emax <= 0 or int(emax) != emax:
80 121 storres
        return None
81 121 storres
    precision = number.precision()
82 121 storres
    RF  = RealField(precision)
83 125 storres
    if number == 0:
84 125 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
85 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
86 121 storres
    # when computing number.log2().
87 121 storres
    RRF = RealField(max(2048, 2 * precision))
88 121 storres
    # number = 0 special case, the binade bounds are
89 121 storres
    # [0, 2^emin - 2^(emin-precision)]
90 121 storres
    # Begin general case
91 119 storres
    l2 = RRF(number).abs().log2()
92 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
93 121 storres
    if l2 >= emax + 1:
94 121 storres
        if number > 0:
95 125 storres
            return (RF(2^(emax+1)), RF(+infinity) )
96 121 storres
        else:
97 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
98 165 storres
    # Regular case cont'd.
99 119 storres
    offset = int(l2)
100 121 storres
    # number.abs() >= 1.
101 119 storres
    if l2 >= 0:
102 119 storres
        if number >= 0:
103 119 storres
            lb = RF(2^offset)
104 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
105 119 storres
        else: #number < 0
106 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
107 119 storres
            ub = -RF(2^offset)
108 121 storres
    else: # log2 < 0, number.abs() < 1.
109 119 storres
        if l2 < emin: # Denormal
110 121 storres
           # print "Denormal:", l2
111 119 storres
            if number >= 0:
112 119 storres
                lb = RF(0)
113 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
114 119 storres
            else: # number <= 0
115 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
116 119 storres
                ub = RF(0)
117 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
118 119 storres
            if number >= 0:
119 121 storres
                if int(l2) == l2:
120 121 storres
                    lb = RF(2^(offset))
121 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
122 121 storres
                else:
123 121 storres
                    lb = RF(2^(offset-1))
124 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
125 119 storres
            else: # number < 0
126 121 storres
                if int(l2) == l2: # Binade limit.
127 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
128 121 storres
                    ub = -RF(2^(offset))
129 121 storres
                else:
130 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
131 121 storres
                    ub = -RF(2^(offset-1))
132 121 storres
        else: # l2== emin, number == +/-2^emin
133 119 storres
            if number >= 0:
134 119 storres
                lb = RF(2^(offset))
135 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
136 119 storres
            else: # number < 0
137 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
138 119 storres
                ub = -RF(2^(offset))
139 119 storres
    return (lb, ub)
140 119 storres
# End slz_compute_binade_bounds
141 119 storres
#
142 123 storres
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
143 123 storres
                                                 alpha,
144 123 storres
                                                 N,
145 123 storres
                                                 iBound,
146 223 storres
                                                 tBound,
147 223 storres
                                                 debug = False):
148 123 storres
    """
149 123 storres
    For a given set of arguments (see below), compute a list
150 123 storres
    of "reduced polynomials" that could be used to compute roots
151 123 storres
    of the inputPolynomial.
152 124 storres
    INPUT:
153 124 storres
154 124 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
155 124 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
156 124 storres
    - "N" -- the modulus;
157 124 storres
    - "iBound" -- the bound on the first variable;
158 124 storres
    - "tBound" -- the bound on the second variable.
159 124 storres
160 124 storres
    OUTPUT:
161 124 storres
162 124 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
163 124 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
164 124 storres
    reduced base that comply with the Coppersmith condition.
165 123 storres
    """
166 123 storres
    # Arguments check.
167 123 storres
    if iBound == 0 or tBound == 0:
168 179 storres
        return None
169 123 storres
    # End arguments check.
170 123 storres
    nAtAlpha = N^alpha
171 123 storres
    ## Building polynomials for matrix.
172 123 storres
    polyRing   = inputPolynomial.parent()
173 123 storres
    # Whatever the 2 variables are actually called, we call them
174 123 storres
    # 'i' and 't' in all the variable names.
175 123 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
176 123 storres
    #print polyVars[0], type(polyVars[0])
177 123 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
178 123 storres
                                              tVariable:tVariable * tBound})
179 223 storres
    if debug:
180 223 storres
        polynomialsList = \
181 223 storres
            spo_polynomial_to_polynomials_list_8(initialPolynomial,
182 223 storres
                                                 alpha,
183 223 storres
                                                 N,
184 223 storres
                                                 iBound,
185 223 storres
                                                 tBound,
186 223 storres
                                                 20)
187 223 storres
    else:
188 223 storres
        polynomialsList = \
189 223 storres
            spo_polynomial_to_polynomials_list_8(initialPolynomial,
190 223 storres
                                                 alpha,
191 223 storres
                                                 N,
192 223 storres
                                                 iBound,
193 223 storres
                                                 tBound,
194 223 storres
                                                 0)
195 123 storres
    #print "Polynomials list:", polynomialsList
196 123 storres
    ## Building the proto matrix.
197 123 storres
    knownMonomials = []
198 123 storres
    protoMatrix    = []
199 223 storres
    if debug:
200 223 storres
        for poly in polynomialsList:
201 223 storres
            spo_add_polynomial_coeffs_to_matrix_row(poly,
202 223 storres
                                                    knownMonomials,
203 223 storres
                                                    protoMatrix,
204 223 storres
                                                    20)
205 223 storres
    else:
206 223 storres
        for poly in polynomialsList:
207 223 storres
            spo_add_polynomial_coeffs_to_matrix_row(poly,
208 223 storres
                                                    knownMonomials,
209 223 storres
                                                    protoMatrix,
210 223 storres
                                                    0)
211 123 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
212 123 storres
    #print matrixToReduce
213 123 storres
    ## Reduction and checking.
214 163 storres
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
215 163 storres
    #  error message issued when previous code was used.
216 163 storres
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
217 163 storres
    reducedMatrix = matrixToReduce.LLL(fp=None)
218 123 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
219 123 storres
    if not isLLLReduced:
220 179 storres
        return None
221 123 storres
    monomialsCount     = len(knownMonomials)
222 123 storres
    monomialsCountSqrt = sqrt(monomialsCount)
223 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
224 123 storres
    #print reducedMatrix
225 123 storres
    ## Check the Coppersmith condition for each row and build the reduced
226 123 storres
    #  polynomials.
227 123 storres
    ccReducedPolynomialsList = []
228 123 storres
    for row in reducedMatrix.rows():
229 123 storres
        l2Norm = row.norm(2)
230 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
231 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
232 125 storres
            #print l2Norm.n()
233 123 storres
            ccReducedPolynomial = \
234 123 storres
                slz_compute_reduced_polynomial(row,
235 123 storres
                                               knownMonomials,
236 123 storres
                                               iVariable,
237 123 storres
                                               iBound,
238 123 storres
                                               tVariable,
239 123 storres
                                               tBound)
240 123 storres
            if not ccReducedPolynomial is None:
241 123 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
242 123 storres
        else:
243 125 storres
            #print l2Norm.n() , ">", nAtAlpha
244 123 storres
            pass
245 123 storres
    if len(ccReducedPolynomialsList) < 2:
246 125 storres
        print "Less than 2 Coppersmith condition compliant vectors."
247 123 storres
        return ()
248 125 storres
    #print ccReducedPolynomialsList
249 123 storres
    return ccReducedPolynomialsList
250 123 storres
# End slz_compute_coppersmith_reduced_polynomials
251 123 storres
252 212 storres
def slz_compute_coppersmith_reduced_polynomials_with_lattice_volume(inputPolynomial,
253 212 storres
                                                                    alpha,
254 212 storres
                                                                    N,
255 212 storres
                                                                    iBound,
256 212 storres
                                                                    tBound):
257 212 storres
    """
258 212 storres
    For a given set of arguments (see below), compute a list
259 212 storres
    of "reduced polynomials" that could be used to compute roots
260 212 storres
    of the inputPolynomial.
261 212 storres
    Print the volume of the initial basis as well.
262 212 storres
    INPUT:
263 212 storres
264 212 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
265 212 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
266 212 storres
    - "N" -- the modulus;
267 212 storres
    - "iBound" -- the bound on the first variable;
268 212 storres
    - "tBound" -- the bound on the second variable.
269 212 storres
270 212 storres
    OUTPUT:
271 212 storres
272 212 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
273 212 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
274 212 storres
    reduced base that comply with the Coppersmith condition.
275 212 storres
    """
276 212 storres
    # Arguments check.
277 212 storres
    if iBound == 0 or tBound == 0:
278 212 storres
        return None
279 212 storres
    # End arguments check.
280 212 storres
    nAtAlpha = N^alpha
281 212 storres
    ## Building polynomials for matrix.
282 212 storres
    polyRing   = inputPolynomial.parent()
283 212 storres
    # Whatever the 2 variables are actually called, we call them
284 212 storres
    # 'i' and 't' in all the variable names.
285 212 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
286 212 storres
    #print polyVars[0], type(polyVars[0])
287 212 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
288 212 storres
                                              tVariable:tVariable * tBound})
289 212 storres
##    polynomialsList = \
290 212 storres
##        spo_polynomial_to_polynomials_list_8(initialPolynomial,
291 212 storres
##        spo_polynomial_to_polynomials_list_5(initialPolynomial,
292 212 storres
    polynomialsList = \
293 212 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
294 212 storres
                                             alpha,
295 212 storres
                                             N,
296 212 storres
                                             iBound,
297 212 storres
                                             tBound,
298 212 storres
                                             0)
299 212 storres
    #print "Polynomials list:", polynomialsList
300 212 storres
    ## Building the proto matrix.
301 212 storres
    knownMonomials = []
302 212 storres
    protoMatrix    = []
303 212 storres
    for poly in polynomialsList:
304 212 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
305 212 storres
                                                knownMonomials,
306 212 storres
                                                protoMatrix,
307 212 storres
                                                0)
308 212 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
309 212 storres
    matrixToReduceTranspose = matrixToReduce.transpose()
310 212 storres
    squareMatrix = matrixToReduce * matrixToReduceTranspose
311 212 storres
    squareMatDet = det(squareMatrix)
312 212 storres
    latticeVolume = sqrt(squareMatDet)
313 212 storres
    print "Lattice volume:", latticeVolume.n()
314 212 storres
    print "Lattice volume / N:", (latticeVolume/N).n()
315 212 storres
    #print matrixToReduce
316 212 storres
    ## Reduction and checking.
317 212 storres
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
318 212 storres
    #  error message issued when previous code was used.
319 212 storres
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
320 212 storres
    reductionTimeStart = cputime()
321 212 storres
    reducedMatrix = matrixToReduce.LLL(fp=None)
322 212 storres
    reductionTime = cputime(reductionTimeStart)
323 212 storres
    print "Reduction time:", reductionTime
324 212 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
325 212 storres
    if not isLLLReduced:
326 212 storres
        return None
327 212 storres
    monomialsCount     = len(knownMonomials)
328 212 storres
    monomialsCountSqrt = sqrt(monomialsCount)
329 212 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
330 212 storres
    #print reducedMatrix
331 212 storres
    ## Check the Coppersmith condition for each row and build the reduced
332 212 storres
    #  polynomials.
333 212 storres
    ccReducedPolynomialsList = []
334 212 storres
    for row in reducedMatrix.rows():
335 212 storres
        l2Norm = row.norm(2)
336 212 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
337 212 storres
            #print (l2Norm * monomialsCountSqrt).n()
338 212 storres
            #print l2Norm.n()
339 212 storres
            ccReducedPolynomial = \
340 212 storres
                slz_compute_reduced_polynomial(row,
341 212 storres
                                               knownMonomials,
342 212 storres
                                               iVariable,
343 212 storres
                                               iBound,
344 212 storres
                                               tVariable,
345 212 storres
                                               tBound)
346 212 storres
            if not ccReducedPolynomial is None:
347 212 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
348 212 storres
        else:
349 212 storres
            #print l2Norm.n() , ">", nAtAlpha
350 212 storres
            pass
351 212 storres
    if len(ccReducedPolynomialsList) < 2:
352 212 storres
        print "Less than 2 Coppersmith condition compliant vectors."
353 212 storres
        return ()
354 212 storres
    #print ccReducedPolynomialsList
355 212 storres
    return ccReducedPolynomialsList
356 212 storres
# End slz_compute_coppersmith_reduced_polynomials_with_lattice volume
357 212 storres
358 219 storres
def slz_compute_initial_lattice_matrix(inputPolynomial,
359 219 storres
                                       alpha,
360 219 storres
                                       N,
361 219 storres
                                       iBound,
362 219 storres
                                       tBound):
363 219 storres
    """
364 219 storres
    For a given set of arguments (see below), compute the initial lattice
365 219 storres
    that could be reduced.
366 219 storres
    INPUT:
367 219 storres
368 219 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
369 219 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
370 219 storres
    - "N" -- the modulus;
371 219 storres
    - "iBound" -- the bound on the first variable;
372 219 storres
    - "tBound" -- the bound on the second variable.
373 219 storres
374 219 storres
    OUTPUT:
375 219 storres
376 219 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
377 219 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
378 219 storres
    reduced base that comply with the Coppersmith condition.
379 219 storres
    """
380 219 storres
    # Arguments check.
381 219 storres
    if iBound == 0 or tBound == 0:
382 219 storres
        return None
383 219 storres
    # End arguments check.
384 219 storres
    nAtAlpha = N^alpha
385 219 storres
    ## Building polynomials for matrix.
386 219 storres
    polyRing   = inputPolynomial.parent()
387 219 storres
    # Whatever the 2 variables are actually called, we call them
388 219 storres
    # 'i' and 't' in all the variable names.
389 219 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
390 219 storres
    #print polyVars[0], type(polyVars[0])
391 219 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
392 219 storres
                                              tVariable:tVariable * tBound})
393 219 storres
    polynomialsList = \
394 219 storres
        spo_polynomial_to_polynomials_list_8(initialPolynomial,
395 219 storres
                                             alpha,
396 219 storres
                                             N,
397 219 storres
                                             iBound,
398 219 storres
                                             tBound,
399 219 storres
                                             0)
400 219 storres
    #print "Polynomials list:", polynomialsList
401 219 storres
    ## Building the proto matrix.
402 219 storres
    knownMonomials = []
403 219 storres
    protoMatrix    = []
404 219 storres
    for poly in polynomialsList:
405 219 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
406 219 storres
                                                knownMonomials,
407 219 storres
                                                protoMatrix,
408 219 storres
                                                0)
409 219 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
410 219 storres
    return matrixToReduce
411 219 storres
# End slz_compute_initial_lattice_matrix.
412 219 storres
413 122 storres
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
414 122 storres
                                                 alpha,
415 122 storres
                                                 N,
416 122 storres
                                                 iBound,
417 122 storres
                                                 tBound):
418 122 storres
    """
419 123 storres
    For a given set of arguments (see below), compute the polynomial modular
420 122 storres
    roots, if any.
421 124 storres
422 122 storres
    """
423 123 storres
    # Arguments check.
424 123 storres
    if iBound == 0 or tBound == 0:
425 123 storres
        return set()
426 123 storres
    # End arguments check.
427 122 storres
    nAtAlpha = N^alpha
428 122 storres
    ## Building polynomials for matrix.
429 122 storres
    polyRing   = inputPolynomial.parent()
430 122 storres
    # Whatever the 2 variables are actually called, we call them
431 122 storres
    # 'i' and 't' in all the variable names.
432 122 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
433 125 storres
    ccReducedPolynomialsList = \
434 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
435 125 storres
                                                     alpha,
436 125 storres
                                                     N,
437 125 storres
                                                     iBound,
438 125 storres
                                                     tBound)
439 125 storres
    if len(ccReducedPolynomialsList) == 0:
440 125 storres
        return set()
441 122 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
442 122 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
443 122 storres
    # Try to mix and match all the polynomial pairs built from the
444 122 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
445 122 storres
    resultantsInITuplesList = []
446 122 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
447 122 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
448 122 storres
                                     len(ccReducedPolynomialsList)):
449 122 storres
            # Compute the resultant in resultants in the
450 122 storres
            # first variable (is it the optimal choice?).
451 122 storres
            resultantInI = \
452 122 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
453 122 storres
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
454 122 storres
            #print "Resultant", resultantInI
455 122 storres
            # Test algebraic independence.
456 122 storres
            if not resultantInI.is_zero():
457 122 storres
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
458 122 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
459 122 storres
                                                 resultantInI))
460 122 storres
    # If no non zero resultant was found: we can't get no algebraically
461 122 storres
    # independent polynomials pair. Give up!
462 122 storres
    if len(resultantsInITuplesList) == 0:
463 123 storres
        return set()
464 123 storres
    #print resultantsInITuplesList
465 122 storres
    # Compute the roots.
466 122 storres
    Zi = ZZ[str(iVariable)]
467 122 storres
    Zt = ZZ[str(tVariable)]
468 122 storres
    polynomialRootsSet = set()
469 122 storres
    # First, solve in the second variable since resultants are in the first
470 122 storres
    # variable.
471 122 storres
    for resultantInITuple in resultantsInITuplesList:
472 122 storres
        tRootsList = Zt(resultantInITuple[2]).roots()
473 122 storres
        # For each tRoot, compute the corresponding iRoots and check
474 123 storres
        # them in the input polynomial.
475 122 storres
        for tRoot in tRootsList:
476 123 storres
            #print "tRoot:", tRoot
477 122 storres
            # Roots returned by root() are (value, multiplicity) tuples.
478 122 storres
            iRootsList = \
479 122 storres
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
480 123 storres
            print iRootsList
481 122 storres
            # The iRootsList can be empty, hence the test.
482 122 storres
            if len(iRootsList) != 0:
483 122 storres
                for iRoot in iRootsList:
484 122 storres
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
485 122 storres
                    # polyEvalModN must be an integer.
486 122 storres
                    if polyEvalModN == int(polyEvalModN):
487 122 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
488 122 storres
    return polynomialRootsSet
489 122 storres
# End slz_compute_integer_polynomial_modular_roots.
490 122 storres
#
491 125 storres
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
492 125 storres
                                                 alpha,
493 125 storres
                                                 N,
494 125 storres
                                                 iBound,
495 125 storres
                                                 tBound):
496 125 storres
    """
497 125 storres
    For a given set of arguments (see below), compute the polynomial modular
498 125 storres
    roots, if any.
499 125 storres
    This version differs in the way resultants are computed.
500 125 storres
    """
501 125 storres
    # Arguments check.
502 125 storres
    if iBound == 0 or tBound == 0:
503 125 storres
        return set()
504 125 storres
    # End arguments check.
505 125 storres
    nAtAlpha = N^alpha
506 125 storres
    ## Building polynomials for matrix.
507 125 storres
    polyRing   = inputPolynomial.parent()
508 125 storres
    # Whatever the 2 variables are actually called, we call them
509 125 storres
    # 'i' and 't' in all the variable names.
510 125 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
511 125 storres
    #print polyVars[0], type(polyVars[0])
512 125 storres
    ccReducedPolynomialsList = \
513 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
514 125 storres
                                                     alpha,
515 125 storres
                                                     N,
516 125 storres
                                                     iBound,
517 125 storres
                                                     tBound)
518 125 storres
    if len(ccReducedPolynomialsList) == 0:
519 125 storres
        return set()
520 125 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
521 125 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
522 125 storres
    # Try to mix and match all the polynomial pairs built from the
523 125 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
524 125 storres
    resultantsInTTuplesList = []
525 125 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
526 125 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
527 125 storres
                                     len(ccReducedPolynomialsList)):
528 125 storres
            # Compute the resultant in resultants in the
529 125 storres
            # first variable (is it the optimal choice?).
530 125 storres
            resultantInT = \
531 125 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
532 125 storres
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
533 125 storres
            #print "Resultant", resultantInT
534 125 storres
            # Test algebraic independence.
535 125 storres
            if not resultantInT.is_zero():
536 125 storres
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
537 125 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
538 125 storres
                                                 resultantInT))
539 125 storres
    # If no non zero resultant was found: we can't get no algebraically
540 125 storres
    # independent polynomials pair. Give up!
541 125 storres
    if len(resultantsInTTuplesList) == 0:
542 125 storres
        return set()
543 125 storres
    #print resultantsInITuplesList
544 125 storres
    # Compute the roots.
545 125 storres
    Zi = ZZ[str(iVariable)]
546 125 storres
    Zt = ZZ[str(tVariable)]
547 125 storres
    polynomialRootsSet = set()
548 125 storres
    # First, solve in the second variable since resultants are in the first
549 125 storres
    # variable.
550 125 storres
    for resultantInTTuple in resultantsInTTuplesList:
551 125 storres
        iRootsList = Zi(resultantInTTuple[2]).roots()
552 125 storres
        # For each iRoot, compute the corresponding tRoots and check
553 125 storres
        # them in the input polynomial.
554 125 storres
        for iRoot in iRootsList:
555 125 storres
            #print "iRoot:", iRoot
556 125 storres
            # Roots returned by root() are (value, multiplicity) tuples.
557 125 storres
            tRootsList = \
558 125 storres
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
559 125 storres
            print tRootsList
560 125 storres
            # The tRootsList can be empty, hence the test.
561 125 storres
            if len(tRootsList) != 0:
562 125 storres
                for tRoot in tRootsList:
563 125 storres
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
564 125 storres
                    # polyEvalModN must be an integer.
565 125 storres
                    if polyEvalModN == int(polyEvalModN):
566 125 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
567 125 storres
    return polynomialRootsSet
568 125 storres
# End slz_compute_integer_polynomial_modular_roots_2.
569 125 storres
#
570 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
571 218 storres
                                        upperBoundSa, approxAccurSa,
572 218 storres
                                        precSa=None):
573 61 storres
    """
574 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
575 61 storres
    a polynomial that approximates the function on a an interval starting
576 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
577 61 storres
    approximates with the expected precision.
578 61 storres
    The interval upper bound is lowered until the expected approximation
579 61 storres
    precision is reached.
580 61 storres
    The polynomial, the bounds, the center of the interval and the error
581 61 storres
    are returned.
582 156 storres
    OUTPUT:
583 124 storres
    A tuple made of 4 Sollya objects:
584 124 storres
    - a polynomial;
585 124 storres
    - an range (an interval, not in the sense of number given as an interval);
586 124 storres
    - the center of the interval;
587 124 storres
    - the maximum error in the approximation of the input functionSo by the
588 218 storres
      output polynomial ; this error <= approxAccurSaS.
589 124 storres
590 61 storres
    """
591 218 storres
    #print"In slz_compute_polynomial_and_interval..."
592 166 storres
    ## Superficial argument check.
593 166 storres
    if lowerBoundSa > upperBoundSa:
594 166 storres
        return None
595 218 storres
    ## Change Sollya precision, if requested.
596 218 storres
    if precSa is None:
597 218 storres
        precSa = ceil((RR('1.5') * abs(RR(approxAccurSa).log2())) / 64) * 64
598 218 storres
        #print "Computed internal precision:", precSa
599 218 storres
        if precSa < 192:
600 218 storres
            precSa = 192
601 226 storres
    sollyaPrecChanged = False
602 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
603 226 storres
    if precSa > initialSollyaPrecSa:
604 226 storres
        if precSa <= 2:
605 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
606 226 storres
        pobyso_set_prec_sa_so(precSa)
607 218 storres
        sollyaPrecChanged = True
608 61 storres
    RRR = lowerBoundSa.parent()
609 176 storres
    intervalShrinkConstFactorSa = RRR('0.9')
610 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
611 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
612 61 storres
    currentUpperBoundSa = upperBoundSa
613 61 storres
    currentLowerBoundSa = lowerBoundSa
614 61 storres
    # What we want here is the polynomial without the variable change,
615 61 storres
    # since our actual variable will be x-intervalCenter defined over the
616 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
617 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
618 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
619 61 storres
                                                    currentRangeSo,
620 61 storres
                                                    absoluteErrorTypeSo)
621 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
622 218 storres
    while maxErrorSa > approxAccurSa:
623 181 storres
        print "++Approximation error:", maxErrorSa.n()
624 81 storres
        sollya_lib_clear_obj(polySo)
625 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
626 120 storres
        sollya_lib_clear_obj(maxErrorSo)
627 181 storres
        # Very empirical shrinking factor.
628 218 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
629 181 storres
        print "Shrink factor:", \
630 181 storres
              shrinkFactorSa.n(), \
631 181 storres
              intervalShrinkConstFactorSa
632 182 storres
        print
633 218 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
634 61 storres
        #print "Error ratio: ", errorRatioSa
635 181 storres
        # Make sure interval shrinks.
636 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
637 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
638 81 storres
            #print "Fixed"
639 61 storres
        else:
640 81 storres
            actualShrinkFactorSa = shrinkFactorSa
641 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
642 81 storres
            #print shrinkFactorSa, maxErrorSa
643 101 storres
        #print "Shrink factor", actualShrinkFactorSa
644 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
645 181 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
646 181 storres
                                actualShrinkFactorSa
647 71 storres
        #print "Current upper bound:", currentUpperBoundSa
648 61 storres
        sollya_lib_clear_obj(currentRangeSo)
649 181 storres
        # Check what is left with the bounds.
650 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
651 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
652 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
653 86 storres
            print "Can't find an interval."
654 86 storres
            print "Use either or both a higher polynomial degree or a higher",
655 86 storres
            print "internal precision."
656 86 storres
            print "Aborting!"
657 218 storres
            if sollyaPrecChanged:
658 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
659 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
660 218 storres
            return None
661 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
662 61 storres
                                                      currentUpperBoundSa)
663 86 storres
        # print "New interval:",
664 86 storres
        # pobyso_autoprint(currentRangeSo)
665 120 storres
        #print "Second Taylor expansion call."
666 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
667 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
668 61 storres
                                                        currentRangeSo,
669 61 storres
                                                        absoluteErrorTypeSo)
670 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
671 85 storres
        #print "Max errorSo:",
672 85 storres
        #pobyso_autoprint(maxErrorSo)
673 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
674 85 storres
        #print "Max errorSa:", maxErrorSa
675 85 storres
        #print "Sollya prec:",
676 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
677 218 storres
    # End while
678 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
679 218 storres
    if sollyaPrecChanged:
680 226 storres
        pobyso_set_prec_so_so(initialSollyaPrecSo)
681 226 storres
    sollya_lib_clear_obj(initialSollyaPrecSo)
682 176 storres
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
683 81 storres
# End slz_compute_polynomial_and_interval
684 218 storres
685 218 storres
def slz_compute_polynomial_and_interval_01(functionSo, degreeSo, lowerBoundSa,
686 218 storres
                                        upperBoundSa, approxAccurSa,
687 219 storres
                                        sollyaPrecSa=None, debug=False):
688 219 storres
    """
689 219 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
690 219 storres
    a polynomial that approximates the function on a an interval starting
691 219 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
692 219 storres
    approximates with the expected precision.
693 219 storres
    The interval upper bound is lowered until the expected approximation
694 219 storres
    precision is reached.
695 219 storres
    The polynomial, the bounds, the center of the interval and the error
696 219 storres
    are returned.
697 219 storres
    OUTPUT:
698 219 storres
    A tuple made of 4 Sollya objects:
699 219 storres
    - a polynomial;
700 219 storres
    - an range (an interval, not in the sense of number given as an interval);
701 219 storres
    - the center of the interval;
702 219 storres
    - the maximum error in the approximation of the input functionSo by the
703 219 storres
      output polynomial ; this error <= approxAccurSaS.
704 219 storres
705 219 storres
    """
706 219 storres
    #print"In slz_compute_polynomial_and_interval..."
707 219 storres
    ## Superficial argument check.
708 219 storres
    if lowerBoundSa > upperBoundSa:
709 225 storres
        print inspect.stack()[0][3], ": lower bound is larger than upper bound. "
710 219 storres
        return None
711 219 storres
    ## Change Sollya precision, if requested.
712 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
713 225 storres
    sollyaPrecChangedSa = False
714 225 storres
    if sollyaPrecSa is None:
715 226 storres
        sollyaPrecSa = initialSollyaPrecSa
716 219 storres
    else:
717 226 storres
        if sollyaPrecSa > initialSollyaPrecSa:
718 226 storres
            if sollyaPrecSa <= 2:
719 226 storres
                print inspect.stack()[0][3], ": precision change <= 2 requested."
720 225 storres
            pobyso_set_prec_sa_so(sollyaPrecSa)
721 225 storres
            sollyaPrecChangedSa = True
722 225 storres
    ## Other initializations and data recovery.
723 219 storres
    RRR = lowerBoundSa.parent()
724 219 storres
    intervalShrinkConstFactorSa = RRR('0.9')
725 219 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
726 219 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
727 219 storres
    currentUpperBoundSa = upperBoundSa
728 219 storres
    currentLowerBoundSa = lowerBoundSa
729 219 storres
    # What we want here is the polynomial without the variable change,
730 219 storres
    # since our actual variable will be x-intervalCenter defined over the
731 219 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
732 219 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
733 219 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
734 219 storres
                                                    currentRangeSo,
735 219 storres
                                                    absoluteErrorTypeSo)
736 219 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
737 219 storres
    while maxErrorSa > approxAccurSa:
738 219 storres
        print "++Approximation error:", maxErrorSa.n()
739 219 storres
        sollya_lib_clear_obj(polySo)
740 219 storres
        sollya_lib_clear_obj(intervalCenterSo)
741 219 storres
        sollya_lib_clear_obj(maxErrorSo)
742 219 storres
        # Very empirical shrinking factor.
743 219 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
744 219 storres
        print "Shrink factor:", \
745 219 storres
              shrinkFactorSa.n(), \
746 219 storres
              intervalShrinkConstFactorSa
747 219 storres
        print
748 219 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
749 219 storres
        #print "Error ratio: ", errorRatioSa
750 219 storres
        # Make sure interval shrinks.
751 219 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
752 219 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
753 219 storres
            #print "Fixed"
754 219 storres
        else:
755 219 storres
            actualShrinkFactorSa = shrinkFactorSa
756 219 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
757 219 storres
            #print shrinkFactorSa, maxErrorSa
758 219 storres
        #print "Shrink factor", actualShrinkFactorSa
759 219 storres
        currentUpperBoundSa = currentLowerBoundSa + \
760 219 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
761 219 storres
                                actualShrinkFactorSa
762 219 storres
        #print "Current upper bound:", currentUpperBoundSa
763 219 storres
        sollya_lib_clear_obj(currentRangeSo)
764 219 storres
        # Check what is left with the bounds.
765 219 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
766 219 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
767 219 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
768 219 storres
            print "Can't find an interval."
769 219 storres
            print "Use either or both a higher polynomial degree or a higher",
770 219 storres
            print "internal precision."
771 219 storres
            print "Aborting!"
772 225 storres
            if sollyaPrecChangedSa:
773 225 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
774 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
775 219 storres
            return None
776 219 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
777 219 storres
                                                      currentUpperBoundSa)
778 219 storres
        # print "New interval:",
779 219 storres
        # pobyso_autoprint(currentRangeSo)
780 219 storres
        #print "Second Taylor expansion call."
781 219 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
782 219 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
783 219 storres
                                                        currentRangeSo,
784 219 storres
                                                        absoluteErrorTypeSo)
785 219 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
786 219 storres
        #print "Max errorSo:",
787 219 storres
        #pobyso_autoprint(maxErrorSo)
788 219 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
789 219 storres
        #print "Max errorSa:", maxErrorSa
790 219 storres
        #print "Sollya prec:",
791 219 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
792 219 storres
    # End while
793 219 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
794 226 storres
    print inspect.stack()[0][3], "SollyaPrecSa:", sollyaPrecSa
795 219 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
796 219 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
797 219 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
798 219 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
799 219 storres
    if debug:
800 219 storres
        print "About to call polynomial rounding with:"
801 219 storres
        print "polySo: ",           ; pobyso_autoprint(polySo)
802 219 storres
        print "functionSo: ",       ; pobyso_autoprint(functionSo)
803 219 storres
        print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
804 219 storres
        print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
805 219 storres
        print "itpSo: ",            ; pobyso_autoprint(itpSo)
806 219 storres
        print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
807 219 storres
        print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
808 219 storres
        print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
809 224 storres
    """
810 224 storres
    # Naive rounding.
811 219 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
812 219 storres
    pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
813 219 storres
                                                           functionSo,
814 219 storres
                                                           intervalCenterSo,
815 219 storres
                                                           currentRangeSo,
816 219 storres
                                                           itpSo,
817 219 storres
                                                           ftpSo,
818 219 storres
                                                           maxPrecSo,
819 219 storres
                                                           approxAccurSo)
820 224 storres
    """
821 224 storres
    # Proved rounding.
822 224 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
823 224 storres
        pobyso_round_coefficients_progressive_so_so(polySo,
824 224 storres
                                                    functionSo,
825 224 storres
                                                    maxPrecSo,
826 224 storres
                                                    currentRangeSo,
827 224 storres
                                                    intervalCenterSo,
828 224 storres
                                                    maxErrorSo,
829 224 storres
                                                    approxAccurSo,
830 224 storres
                                                    debug=False)
831 224 storres
    #### Comment out the two next lines when polynomial rounding is activated.
832 224 storres
    #roundedPolySo = sollya_lib_copy_obj(polySo)
833 224 storres
    #roundedPolyMaxErrSo =  sollya_lib_copy_obj(maxErrorSo)
834 219 storres
    sollya_lib_clear_obj(polySo)
835 219 storres
    sollya_lib_clear_obj(maxErrorSo)
836 219 storres
    sollya_lib_clear_obj(itpSo)
837 219 storres
    sollya_lib_clear_obj(ftpSo)
838 219 storres
    sollya_lib_clear_obj(approxAccurSo)
839 225 storres
    if sollyaPrecChangedSa:
840 225 storres
        pobyso_set_prec_so_so(initialSollyaPrecSa)
841 226 storres
    sollya_lib_clear_obj(initialSollyaPrecSa)
842 219 storres
    if debug:
843 219 storres
        print "1: ", ; pobyso_autoprint(roundedPolySo)
844 219 storres
        print "2: ", ; pobyso_autoprint(currentRangeSo)
845 219 storres
        print "3: ", ; pobyso_autoprint(intervalCenterSo)
846 219 storres
        print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
847 219 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
848 219 storres
# End slz_compute_polynomial_and_interval_01
849 219 storres
850 219 storres
def slz_compute_polynomial_and_interval_02(functionSo, degreeSo, lowerBoundSa,
851 219 storres
                                        upperBoundSa, approxAccurSa,
852 227 storres
                                        sollyaPrecSa=None, debug=True ):
853 218 storres
    """
854 218 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
855 218 storres
    a polynomial that approximates the function on a an interval starting
856 218 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
857 218 storres
    approximates with the expected precision.
858 218 storres
    The interval upper bound is lowered until the expected approximation
859 218 storres
    precision is reached.
860 218 storres
    The polynomial, the bounds, the center of the interval and the error
861 218 storres
    are returned.
862 218 storres
    OUTPUT:
863 218 storres
    A tuple made of 4 Sollya objects:
864 218 storres
    - a polynomial;
865 218 storres
    - an range (an interval, not in the sense of number given as an interval);
866 218 storres
    - the center of the interval;
867 218 storres
    - the maximum error in the approximation of the input functionSo by the
868 218 storres
      output polynomial ; this error <= approxAccurSaS.
869 227 storres
    Changes fom v1:
870 227 storres
        extra verbose.
871 218 storres
    """
872 218 storres
    print"In slz_compute_polynomial_and_interval..."
873 218 storres
    ## Superficial argument check.
874 218 storres
    if lowerBoundSa > upperBoundSa:
875 218 storres
        return None
876 218 storres
    ## Change Sollya precision, if requested.
877 226 storres
    sollyaPrecChanged = False
878 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
879 227 storres
    #print "Initial Sollya prec:", initialSollyaPrecSa, type(initialSollyaPrecSa)
880 227 storres
    if sollyaPrecSa is None:
881 226 storres
        sollyaPrecSa = initialSollyaPrecSa
882 226 storres
    else:
883 226 storres
        if sollyaPrecSa <= 2:
884 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
885 218 storres
        pobyso_set_prec_sa_so(sollyaPrecSa)
886 226 storres
        sollyaPrecChanged = True
887 218 storres
    RRR = lowerBoundSa.parent()
888 218 storres
    intervalShrinkConstFactorSa = RRR('0.9')
889 218 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
890 218 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
891 218 storres
    currentUpperBoundSa = upperBoundSa
892 218 storres
    currentLowerBoundSa = lowerBoundSa
893 227 storres
    #pobyso_autoprint(functionSo)
894 227 storres
    #pobyso_autoprint(degreeSo)
895 227 storres
    #pobyso_autoprint(currentRangeSo)
896 227 storres
    #pobyso_autoprint(absoluteErrorTypeSo)
897 227 storres
    ## What we want here is the polynomial without the variable change,
898 227 storres
    #  since our actual variable will be x-intervalCenter defined over the
899 227 storres
    #  domain [lowerBound-intervalCenter , upperBound-intervalCenter].
900 218 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
901 218 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
902 218 storres
                                                    currentRangeSo,
903 218 storres
                                                    absoluteErrorTypeSo)
904 218 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
905 227 storres
    print "...after Taylor expansion."
906 218 storres
    while maxErrorSa > approxAccurSa:
907 218 storres
        print "++Approximation error:", maxErrorSa.n()
908 218 storres
        sollya_lib_clear_obj(polySo)
909 218 storres
        sollya_lib_clear_obj(intervalCenterSo)
910 218 storres
        sollya_lib_clear_obj(maxErrorSo)
911 218 storres
        # Very empirical shrinking factor.
912 218 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
913 218 storres
        print "Shrink factor:", \
914 218 storres
              shrinkFactorSa.n(), \
915 218 storres
              intervalShrinkConstFactorSa
916 218 storres
        print
917 218 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
918 218 storres
        #print "Error ratio: ", errorRatioSa
919 218 storres
        # Make sure interval shrinks.
920 218 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
921 218 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
922 218 storres
            #print "Fixed"
923 218 storres
        else:
924 218 storres
            actualShrinkFactorSa = shrinkFactorSa
925 218 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
926 218 storres
            #print shrinkFactorSa, maxErrorSa
927 218 storres
        #print "Shrink factor", actualShrinkFactorSa
928 218 storres
        currentUpperBoundSa = currentLowerBoundSa + \
929 218 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
930 218 storres
                                actualShrinkFactorSa
931 218 storres
        #print "Current upper bound:", currentUpperBoundSa
932 218 storres
        sollya_lib_clear_obj(currentRangeSo)
933 218 storres
        # Check what is left with the bounds.
934 218 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
935 218 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
936 218 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
937 218 storres
            print "Can't find an interval."
938 218 storres
            print "Use either or both a higher polynomial degree or a higher",
939 218 storres
            print "internal precision."
940 218 storres
            print "Aborting!"
941 226 storres
            if sollyaPrecChanged:
942 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
943 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
944 218 storres
            return None
945 218 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
946 218 storres
                                                      currentUpperBoundSa)
947 218 storres
        # print "New interval:",
948 218 storres
        # pobyso_autoprint(currentRangeSo)
949 218 storres
        #print "Second Taylor expansion call."
950 218 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
951 218 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
952 218 storres
                                                        currentRangeSo,
953 218 storres
                                                        absoluteErrorTypeSo)
954 218 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
955 218 storres
        #print "Max errorSo:",
956 218 storres
        #pobyso_autoprint(maxErrorSo)
957 218 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
958 218 storres
        #print "Max errorSa:", maxErrorSa
959 218 storres
        #print "Sollya prec:",
960 218 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
961 218 storres
    # End while
962 218 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
963 218 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
964 218 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
965 218 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
966 218 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
967 218 storres
    print "About to call polynomial rounding with:"
968 218 storres
    print "polySo: ",           ; pobyso_autoprint(polySo)
969 218 storres
    print "functionSo: ",       ; pobyso_autoprint(functionSo)
970 218 storres
    print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
971 218 storres
    print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
972 218 storres
    print "itpSo: ",            ; pobyso_autoprint(itpSo)
973 218 storres
    print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
974 218 storres
    print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
975 218 storres
    print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
976 218 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
977 218 storres
    pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
978 218 storres
                                                           functionSo,
979 218 storres
                                                           intervalCenterSo,
980 218 storres
                                                           currentRangeSo,
981 218 storres
                                                           itpSo,
982 218 storres
                                                           ftpSo,
983 218 storres
                                                           maxPrecSo,
984 218 storres
                                                           approxAccurSo)
985 218 storres
986 218 storres
    sollya_lib_clear_obj(polySo)
987 218 storres
    sollya_lib_clear_obj(maxErrorSo)
988 218 storres
    sollya_lib_clear_obj(itpSo)
989 218 storres
    sollya_lib_clear_obj(ftpSo)
990 218 storres
    sollya_lib_clear_obj(approxAccurSo)
991 226 storres
    if sollyaPrecChanged:
992 226 storres
        pobyso_set_prec_so_so(initialSollyaPrecSo)
993 226 storres
    sollya_lib_clear_obj(initialSollyaPrecSo)
994 218 storres
    print "1: ", ; pobyso_autoprint(roundedPolySo)
995 218 storres
    print "2: ", ; pobyso_autoprint(currentRangeSo)
996 218 storres
    print "3: ", ; pobyso_autoprint(intervalCenterSo)
997 218 storres
    print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
998 218 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
999 219 storres
# End slz_compute_polynomial_and_interval_02
1000 218 storres
1001 122 storres
def slz_compute_reduced_polynomial(matrixRow,
1002 98 storres
                                    knownMonomials,
1003 106 storres
                                    var1,
1004 98 storres
                                    var1Bound,
1005 106 storres
                                    var2,
1006 99 storres
                                    var2Bound):
1007 98 storres
    """
1008 125 storres
    Compute a polynomial from a single reduced matrix row.
1009 122 storres
    This function was introduced in order to avoid the computation of the
1010 125 storres
    all the polynomials  from the full matrix (even those built from rows
1011 125 storres
    that do no verify the Coppersmith condition) as this may involves
1012 152 storres
    expensive operations over (large) integers.
1013 122 storres
    """
1014 122 storres
    ## Check arguments.
1015 122 storres
    if len(knownMonomials) == 0:
1016 122 storres
        return None
1017 122 storres
    # varNounds can be zero since 0^0 returns 1.
1018 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
1019 122 storres
        return None
1020 122 storres
    ## Initialisations.
1021 122 storres
    polynomialRing = knownMonomials[0].parent()
1022 122 storres
    currentPolynomial = polynomialRing(0)
1023 123 storres
    # TODO: use zip instead of indices.
1024 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
1025 122 storres
        currentCoefficient = matrixRow[colIndex]
1026 122 storres
        if currentCoefficient != 0:
1027 122 storres
            #print "Current coefficient:", currentCoefficient
1028 122 storres
            currentMonomial = knownMonomials[colIndex]
1029 122 storres
            #print "Monomial as multivariate polynomial:", \
1030 122 storres
            #currentMonomial, type(currentMonomial)
1031 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
1032 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
1033 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
1034 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
1035 122 storres
            if degreeInVar1 > 0:
1036 122 storres
                currentCoefficient = \
1037 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
1038 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
1039 122 storres
                #print "Current coefficient(1)", currentCoefficient
1040 122 storres
            if degreeInVar2 > 0:
1041 122 storres
                currentCoefficient = \
1042 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
1043 122 storres
                #print "Current coefficient(2)", currentCoefficient
1044 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
1045 122 storres
            #                                    currentMonomial)
1046 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
1047 122 storres
            #print "Current polynomial:", currentPolynomial
1048 122 storres
        # End if
1049 122 storres
    # End for colIndex.
1050 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
1051 122 storres
    return(currentPolynomial)
1052 122 storres
# End slz_compute_reduced_polynomial
1053 122 storres
#
1054 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
1055 122 storres
                                        knownMonomials,
1056 122 storres
                                        var1,
1057 122 storres
                                        var1Bound,
1058 122 storres
                                        var2,
1059 122 storres
                                        var2Bound):
1060 122 storres
    """
1061 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
1062 122 storres
    """
1063 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
1064 122 storres
                                                knownMonomials,
1065 122 storres
                                                var1,
1066 122 storres
                                                var1Bound,
1067 122 storres
                                                var2,
1068 122 storres
                                                var2Bound)
1069 122 storres
    )
1070 177 storres
#
1071 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
1072 152 storres
                                         knownMonomials,
1073 152 storres
                                         var1,
1074 152 storres
                                         var1Bound,
1075 152 storres
                                         var2,
1076 152 storres
                                         var2Bound):
1077 122 storres
    """
1078 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
1079 98 storres
    from the bounds of each variable, compute the corresponding polynomials
1080 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1081 99 storres
1082 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1083 172 storres
    They set the polynomial type of the output polynomials in list.
1084 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
1085 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1086 152 storres
                           build the polynomials;
1087 152 storres
    @param var1:           the first variable (of the "right" type);
1088 152 storres
    @param var1Bound:      the first variable bound;
1089 152 storres
    @param var2:           the second variable (of the "right" type);
1090 152 storres
    @param var2Bound:      the second variable bound.
1091 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
1092 152 storres
             and scaled down with the bounds
1093 98 storres
    """
1094 99 storres
1095 98 storres
    # TODO: check input arguments.
1096 98 storres
    reducedPolynomials = []
1097 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1098 98 storres
    for matrixRow in reducedMatrix.rows():
1099 102 storres
        currentPolynomial = 0
1100 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
1101 98 storres
            currentCoefficient = matrixRow[colIndex]
1102 106 storres
            if currentCoefficient != 0:
1103 106 storres
                #print "Current coefficient:", currentCoefficient
1104 106 storres
                currentMonomial = knownMonomials[colIndex]
1105 106 storres
                parentRing = currentMonomial.parent()
1106 106 storres
                #print "Monomial as multivariate polynomial:", \
1107 106 storres
                #currentMonomial, type(currentMonomial)
1108 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1109 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
1110 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1111 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
1112 106 storres
                if degreeInVar1 > 0:
1113 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1114 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1115 106 storres
                    #print "Current coefficient(1)", currentCoefficient
1116 106 storres
                if degreeInVar2 > 0:
1117 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1118 106 storres
                    #print "Current coefficient(2)", currentCoefficient
1119 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1120 106 storres
                #                                    currentMonomial)
1121 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1122 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1123 168 storres
                    #print "!!!! constant term !!!!"
1124 106 storres
                #print "Current polynomial:", currentPolynomial
1125 106 storres
            # End if
1126 106 storres
        # End for colIndex.
1127 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1128 99 storres
        reducedPolynomials.append(currentPolynomial)
1129 98 storres
    return reducedPolynomials
1130 177 storres
# End slz_compute_reduced_polynomials_list.
1131 98 storres
1132 177 storres
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
1133 177 storres
                                                   knownMonomials,
1134 177 storres
                                                   var1,
1135 177 storres
                                                   var1Bound,
1136 177 storres
                                                   var2,
1137 177 storres
                                                   var2Bound):
1138 177 storres
    """
1139 177 storres
    From a list of rows, holding the coefficients, from a monomials list,
1140 177 storres
    from the bounds of each variable, compute the corresponding polynomials
1141 177 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1142 177 storres
1143 177 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1144 177 storres
    They set the polynomial type of the output polynomials in list.
1145 177 storres
    @param rowsList:       the reduced matrix as output from LLL;
1146 177 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1147 177 storres
                           build the polynomials;
1148 177 storres
    @param var1:           the first variable (of the "right" type);
1149 177 storres
    @param var1Bound:      the first variable bound;
1150 177 storres
    @param var2:           the second variable (of the "right" type);
1151 177 storres
    @param var2Bound:      the second variable bound.
1152 177 storres
    @return: a list of polynomials obtained with the reduced coefficients
1153 177 storres
             and scaled down with the bounds
1154 177 storres
    """
1155 177 storres
1156 177 storres
    # TODO: check input arguments.
1157 177 storres
    reducedPolynomials = []
1158 177 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1159 177 storres
    for matrixRow in rowsList:
1160 177 storres
        currentPolynomial = 0
1161 177 storres
        for colIndex in xrange(0, len(knownMonomials)):
1162 177 storres
            currentCoefficient = matrixRow[colIndex]
1163 177 storres
            if currentCoefficient != 0:
1164 177 storres
                #print "Current coefficient:", currentCoefficient
1165 177 storres
                currentMonomial = knownMonomials[colIndex]
1166 177 storres
                parentRing = currentMonomial.parent()
1167 177 storres
                #print "Monomial as multivariate polynomial:", \
1168 177 storres
                #currentMonomial, type(currentMonomial)
1169 177 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1170 177 storres
                #print "Degree in var", var1, ":", degreeInVar1
1171 177 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1172 177 storres
                #print "Degree in var", var2, ":", degreeInVar2
1173 177 storres
                if degreeInVar1 > 0:
1174 177 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1175 177 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1176 177 storres
                    #print "Current coefficient(1)", currentCoefficient
1177 177 storres
                if degreeInVar2 > 0:
1178 177 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1179 177 storres
                    #print "Current coefficient(2)", currentCoefficient
1180 177 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1181 177 storres
                #                                    currentMonomial)
1182 177 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1183 177 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1184 177 storres
                    #print "!!!! constant term !!!!"
1185 177 storres
                #print "Current polynomial:", currentPolynomial
1186 177 storres
            # End if
1187 177 storres
        # End for colIndex.
1188 177 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1189 177 storres
        reducedPolynomials.append(currentPolynomial)
1190 177 storres
    return reducedPolynomials
1191 177 storres
# End slz_compute_reduced_polynomials_list_from_rows.
1192 177 storres
#
1193 114 storres
def slz_compute_scaled_function(functionSa,
1194 114 storres
                                lowerBoundSa,
1195 114 storres
                                upperBoundSa,
1196 156 storres
                                floatingPointPrecSa,
1197 156 storres
                                debug=False):
1198 72 storres
    """
1199 72 storres
    From a function, compute the scaled function whose domain
1200 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
1201 72 storres
    Return a tuple:
1202 72 storres
    [0]: the scaled function
1203 72 storres
    [1]: the scaled domain lower bound
1204 72 storres
    [2]: the scaled domain upper bound
1205 72 storres
    [3]: the scaled image lower bound
1206 72 storres
    [4]: the scaled image upper bound
1207 72 storres
    """
1208 177 storres
    ## The variable can be called anything.
1209 80 storres
    x = functionSa.variables()[0]
1210 72 storres
    # Scalling the domain -> [1,2[.
1211 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
1212 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
1213 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
1214 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
1215 156 storres
    if debug:
1216 156 storres
        print "domainScalingExpression for argument :", \
1217 156 storres
        invDomainScalingExpressionSa
1218 190 storres
        print "function: ", functionSa
1219 190 storres
    ff = functionSa.subs({x : domainScalingExpressionSa})
1220 190 storres
    ## Bless expression as a function.
1221 190 storres
    ff = ff.function(x)
1222 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
1223 177 storres
    #domainScalingFunction(x) = invDomainScalingExpressionSa
1224 177 storres
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
1225 151 storres
    scaledLowerBoundSa = \
1226 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
1227 151 storres
    scaledUpperBoundSa = \
1228 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
1229 156 storres
    if debug:
1230 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
1231 156 storres
              scaledUpperBoundSa
1232 72 storres
    #
1233 72 storres
    # Scalling the image -> [1,2[.
1234 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
1235 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
1236 72 storres
    if flbSa <= fubSa: # Increasing
1237 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
1238 72 storres
    else: # Decreasing
1239 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
1240 156 storres
    if debug:
1241 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
1242 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
1243 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
1244 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
1245 156 storres
    if debug:
1246 156 storres
        print "imageScalingExpression for argument :", \
1247 156 storres
              invImageScalingExpressionSa
1248 72 storres
    iis = invImageScalingExpressionSa.function(x)
1249 72 storres
    fff = iis.subs({x:ff})
1250 156 storres
    if debug:
1251 156 storres
        print "fff:", fff,
1252 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
1253 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
1254 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
1255 151 storres
# End slz_compute_scaled_function
1256 72 storres
1257 179 storres
def slz_fix_bounds_for_binades(lowerBound,
1258 179 storres
                               upperBound,
1259 190 storres
                               func = None,
1260 179 storres
                               domainDirection = -1,
1261 179 storres
                               imageDirection  = -1):
1262 179 storres
    """
1263 179 storres
    Assuming the function is increasing or decreasing over the
1264 179 storres
    [lowerBound, upperBound] interval, return a lower bound lb and
1265 179 storres
    an upper bound ub such that:
1266 179 storres
    - lb and ub belong to the same binade;
1267 179 storres
    - func(lb) and func(ub) belong to the same binade.
1268 179 storres
    domainDirection indicate how bounds move to fit into the same binade:
1269 179 storres
    - a negative value move the upper bound down;
1270 179 storres
    - a positive value move the lower bound up.
1271 179 storres
    imageDirection indicate how bounds move in order to have their image
1272 179 storres
    fit into the same binade, variation of the function is also condidered.
1273 179 storres
    For an increasing function:
1274 179 storres
    - negative value moves the upper bound down (and its image value as well);
1275 179 storres
    - a positive values moves the lower bound up (and its image value as well);
1276 179 storres
    For a decreasing function it is the other way round.
1277 179 storres
    """
1278 179 storres
    ## Arguments check
1279 179 storres
    if lowerBound > upperBound:
1280 179 storres
        return None
1281 190 storres
    if lowerBound == upperBound:
1282 190 storres
        return (lowerBound, upperBound)
1283 179 storres
    if func is None:
1284 179 storres
        return None
1285 179 storres
    #
1286 179 storres
    #varFunc = func.variables()[0]
1287 179 storres
    lb = lowerBound
1288 179 storres
    ub = upperBound
1289 179 storres
    lbBinade = slz_compute_binade(lb)
1290 179 storres
    ubBinade = slz_compute_binade(ub)
1291 179 storres
    ## Domain binade.
1292 179 storres
    while lbBinade != ubBinade:
1293 179 storres
        newIntervalWidth = (ub - lb) / 2
1294 179 storres
        if domainDirection < 0:
1295 179 storres
            ub = lb + newIntervalWidth
1296 179 storres
            ubBinade = slz_compute_binade(ub)
1297 179 storres
        else:
1298 179 storres
            lb = lb + newIntervalWidth
1299 179 storres
            lbBinade = slz_compute_binade(lb)
1300 179 storres
    ## Image binade.
1301 179 storres
    if lb == ub:
1302 179 storres
        return (lb, ub)
1303 179 storres
    lbImg = func(lb)
1304 179 storres
    ubImg = func(ub)
1305 179 storres
    funcIsInc = (ubImg >= lbImg)
1306 179 storres
    lbImgBinade = slz_compute_binade(lbImg)
1307 179 storres
    ubImgBinade = slz_compute_binade(ubImg)
1308 179 storres
    while lbImgBinade != ubImgBinade:
1309 179 storres
        newIntervalWidth = (ub - lb) / 2
1310 179 storres
        if imageDirection < 0:
1311 179 storres
            if funcIsInc:
1312 179 storres
                ub = lb + newIntervalWidth
1313 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1314 179 storres
                #print ubImgBinade
1315 179 storres
            else:
1316 179 storres
                lb = lb + newIntervalWidth
1317 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
1318 179 storres
                #print lbImgBinade
1319 179 storres
        else:
1320 179 storres
            if funcIsInc:
1321 179 storres
                lb = lb + newIntervalWidth
1322 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
1323 179 storres
                #print lbImgBinade
1324 179 storres
            else:
1325 179 storres
                ub = lb + newIntervalWidth
1326 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1327 179 storres
                #print ubImgBinade
1328 179 storres
    # End while lbImgBinade != ubImgBinade:
1329 179 storres
    return (lb, ub)
1330 179 storres
# End slz_fix_bounds_for_binades.
1331 179 storres
1332 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
1333 79 storres
    # Create a polynomial over the rationals.
1334 179 storres
    ratPolynomialRing = QQ[str(polyOfFloat.variables()[0])]
1335 179 storres
    return(ratPolynomialRing(polyOfFloat))
1336 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1337 81 storres
1338 188 storres
def slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(polyOfFloat):
1339 188 storres
    """
1340 188 storres
     Create a polynomial over the rationals where all denominators are
1341 188 storres
     powers of two.
1342 188 storres
    """
1343 188 storres
    polyVariable = polyOfFloat.variables()[0]
1344 188 storres
    RPR = QQ[str(polyVariable)]
1345 188 storres
    polyCoeffs      = polyOfFloat.coefficients()
1346 188 storres
    #print polyCoeffs
1347 188 storres
    polyExponents   = polyOfFloat.exponents()
1348 188 storres
    #print polyExponents
1349 188 storres
    polyDenomPtwoCoeffs = []
1350 188 storres
    for coeff in polyCoeffs:
1351 188 storres
        polyDenomPtwoCoeffs.append(sno_float_to_rat_pow_of_two_denom(coeff))
1352 188 storres
        #print "Converted coefficient:", sno_float_to_rat_pow_of_two_denom(coeff),
1353 188 storres
        #print type(sno_float_to_rat_pow_of_two_denom(coeff))
1354 188 storres
    ratPoly = RPR(0)
1355 188 storres
    #print type(ratPoly)
1356 188 storres
    ## !!! CAUTION !!! Do not use the RPR(coeff * polyVariagle^exponent)
1357 188 storres
    #  The coefficient becomes plainly wrong when exponent == 0.
1358 188 storres
    #  No clue as to why.
1359 188 storres
    for coeff, exponent in zip(polyDenomPtwoCoeffs, polyExponents):
1360 188 storres
        ratPoly += coeff * RPR(polyVariable^exponent)
1361 188 storres
    return ratPoly
1362 188 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1363 188 storres
1364 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
1365 63 storres
                                      lowerBoundSa,
1366 60 storres
                                      upperBoundSa, floatingPointPrecSa,
1367 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
1368 60 storres
    """
1369 60 storres
    Under the assumption that:
1370 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
1371 60 storres
    - lowerBound and upperBound belong to the same binade.
1372 60 storres
    from a:
1373 60 storres
    - function;
1374 60 storres
    - a degree
1375 60 storres
    - a pair of bounds;
1376 60 storres
    - the floating-point precision we work on;
1377 60 storres
    - the internal Sollya precision;
1378 64 storres
    - the requested approximation error
1379 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
1380 61 storres
    It return a list of tuples, each made of:
1381 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
1382 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
1383 61 storres
    - the approximation interval;
1384 72 storres
    - the center, x0, of the interval;
1385 61 storres
    - the corresponding approximation error.
1386 100 storres
    TODO: fix endless looping for some parameters sets.
1387 60 storres
    """
1388 120 storres
    resultArray = []
1389 101 storres
    # Set Sollya to the necessary internal precision.
1390 226 storres
    sollyaPrecChangedSa = False
1391 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
1392 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
1393 226 storres
        if internalSollyaPrecSa <= 2:
1394 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
1395 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
1396 226 storres
        sollyaPrecChangedSa = True
1397 101 storres
    #
1398 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
1399 101 storres
    # Scaled function: [1=,2] -> [1,2].
1400 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
1401 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
1402 115 storres
                slz_compute_scaled_function(functionSa,                       \
1403 115 storres
                                            lowerBoundSa,                     \
1404 115 storres
                                            upperBoundSa,                     \
1405 80 storres
                                            floatingPointPrecSa)
1406 166 storres
    # In case bounds were in the negative real one may need to
1407 166 storres
    # switch scaled bounds.
1408 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
1409 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
1410 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
1411 166 storres
        #print "Switching!"
1412 218 storres
    print "Approximation accuracy: ", RR(approxAccurSa)
1413 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
1414 159 storres
    functionSo = \
1415 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
1416 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
1417 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
1418 61 storres
                                                  scaledUpperBoundSa)
1419 176 storres
1420 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
1421 60 storres
                                              upperBoundSa.parent().precision()))
1422 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
1423 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
1424 176 storres
    while True:
1425 176 storres
        ## Compute the first Taylor expansion.
1426 176 storres
        print "Computing a Taylor expansion..."
1427 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
1428 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
1429 176 storres
                                        currentScaledLowerBoundSa,
1430 176 storres
                                        currentScaledUpperBoundSa,
1431 218 storres
                                        approxAccurSa, internalSollyaPrecSa)
1432 176 storres
        print "...done."
1433 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
1434 176 storres
        #  This value goes to the first variable: polySo. Other variables are
1435 176 storres
        #  not assigned and should not be tested.
1436 176 storres
        if polySo is None:
1437 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
1438 176 storres
            if precChangedSa:
1439 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1440 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1441 176 storres
            sollya_lib_clear_obj(functionSo)
1442 176 storres
            sollya_lib_clear_obj(degreeSo)
1443 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1444 176 storres
            return None
1445 176 storres
        ## Add to the result array.
1446 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
1447 176 storres
        changeVarExpressionSo = \
1448 176 storres
            sollya_lib_build_function_sub( \
1449 176 storres
                              sollya_lib_build_function_free_variable(),
1450 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
1451 176 storres
        polyVarChangedSo = \
1452 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
1453 176 storres
        #### Get rid of the variable change Sollya stuff.
1454 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
1455 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
1456 101 storres
                            intervalCenterSo, maxErrorSo))
1457 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
1458 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1459 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
1460 176 storres
        # If the error and interval are OK a the first try, just return.
1461 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
1462 218 storres
            (errorSa <= approxAccurSa):
1463 176 storres
            if precChangedSa:
1464 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1465 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1466 176 storres
            sollya_lib_clear_obj(functionSo)
1467 176 storres
            sollya_lib_clear_obj(degreeSo)
1468 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1469 101 storres
            #print "Approximation error:", errorSa
1470 176 storres
            return resultArray
1471 176 storres
        ## The returned interval upper bound does not reach the requested upper
1472 176 storres
        #  upper bound: compute the next upper bound.
1473 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
1474 176 storres
        #  enlarge the interval
1475 218 storres
        currentErrorRatio = approxAccurSa / errorSa
1476 176 storres
        ## --|--------------------------------------------------------------|--
1477 176 storres
        #  --|--------------------|--------------------------------------------
1478 176 storres
        #  --|----------------------------|------------------------------------
1479 176 storres
        ## Starting point for the next upper bound.
1480 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
1481 101 storres
        # Compute the increment.
1482 176 storres
        newBoundsWidthSa = \
1483 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
1484 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
1485 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
1486 176 storres
        # Take into account the original interval upper bound.
1487 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
1488 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
1489 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
1490 85 storres
            print "Can't shrink the interval anymore!"
1491 85 storres
            print "You should consider increasing the Sollya internal precision"
1492 85 storres
            print "or the polynomial degree."
1493 85 storres
            print "Giving up!"
1494 176 storres
            if precChangedSa:
1495 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1496 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1497 85 storres
            sollya_lib_clear_obj(functionSo)
1498 85 storres
            sollya_lib_clear_obj(degreeSo)
1499 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1500 85 storres
            return None
1501 176 storres
        # Compute the other expansions.
1502 176 storres
        # Test for insufficient precision.
1503 81 storres
# End slz_get_intervals_and_polynomials
1504 60 storres
1505 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
1506 61 storres
    """
1507 151 storres
    Compute the scaling expression to map an interval that spans at most
1508 166 storres
    a single binade into [1, 2) and the inverse expression as well.
1509 165 storres
    If the interval spans more than one binade, result is wrong since
1510 165 storres
    scaling is only based on the lower bound.
1511 62 storres
    Not very sure that the transformation makes sense for negative numbers.
1512 61 storres
    """
1513 165 storres
    # The "one of the bounds is 0" special case. Here we consider
1514 165 storres
    # the interval as the subnormals binade.
1515 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
1516 165 storres
        # The upper bound is (or should be) positive.
1517 165 storres
        if boundsInterval.endpoints()[0] == 0:
1518 165 storres
            if boundsInterval.endpoints()[1] == 0:
1519 165 storres
                return None
1520 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
1521 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
1522 165 storres
            # The upper bound is a power of two
1523 165 storres
            if binade == l2:
1524 165 storres
                scalingCoeff    = 2^(-binade)
1525 165 storres
                invScalingCoeff = 2^(binade)
1526 165 storres
                scalingOffset   = 1
1527 179 storres
                return \
1528 179 storres
                  ((scalingCoeff * expVar + scalingOffset).function(expVar),
1529 179 storres
                  ((expVar - scalingOffset) * invScalingCoeff).function(expVar))
1530 165 storres
            else:
1531 165 storres
                scalingCoeff    = 2^(-binade-1)
1532 165 storres
                invScalingCoeff = 2^(binade+1)
1533 165 storres
                scalingOffset   = 1
1534 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1535 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1536 165 storres
        # The lower bound is (or should be) negative.
1537 165 storres
        if boundsInterval.endpoints()[1] == 0:
1538 165 storres
            if boundsInterval.endpoints()[0] == 0:
1539 165 storres
                return None
1540 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
1541 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
1542 165 storres
            # The upper bound is a power of two
1543 165 storres
            if binade == l2:
1544 165 storres
                scalingCoeff    = -2^(-binade)
1545 165 storres
                invScalingCoeff = -2^(binade)
1546 165 storres
                scalingOffset   = 1
1547 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1548 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1549 165 storres
            else:
1550 165 storres
                scalingCoeff    = -2^(-binade-1)
1551 165 storres
                invScalingCoeff = -2^(binade+1)
1552 165 storres
                scalingOffset   = 1
1553 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1554 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
1555 165 storres
    # General case
1556 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
1557 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
1558 165 storres
    # We allow for a single exception in binade spanning is when the
1559 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
1560 165 storres
    # "inner bound" + 1.
1561 165 storres
    if boundsInterval.endpoints()[0] > 0:
1562 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
1563 165 storres
        if lbBinade != ubBinade:
1564 165 storres
            print "Different binades."
1565 165 storres
            if ubL2 != ubBinade:
1566 165 storres
                print "Not a power of 2."
1567 165 storres
                return None
1568 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1569 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1570 165 storres
                return None
1571 165 storres
    else:
1572 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
1573 165 storres
        if lbBinade != ubBinade:
1574 165 storres
            print "Different binades."
1575 165 storres
            if lbL2 != lbBinade:
1576 165 storres
                print "Not a power of 2."
1577 165 storres
                return None
1578 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1579 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1580 165 storres
                return None
1581 165 storres
    #print "Lower bound binade:", binade
1582 165 storres
    if boundsInterval.endpoints()[0] > 0:
1583 179 storres
        return \
1584 179 storres
            ((2^(-lbBinade) * expVar).function(expVar),
1585 179 storres
             (2^(lbBinade) * expVar).function(expVar))
1586 165 storres
    else:
1587 179 storres
        return \
1588 179 storres
            ((-(2^(-ubBinade)) * expVar).function(expVar),
1589 179 storres
             (-(2^(ubBinade)) * expVar).function(expVar))
1590 165 storres
"""
1591 165 storres
    # Code sent to attic. Should be the base for a
1592 165 storres
    # "slz_interval_translate_expression" rather than scale.
1593 165 storres
    # Extra control and special cases code  added in
1594 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
1595 165 storres
    # this new function.
1596 62 storres
    # The scaling offset is only used for negative numbers.
1597 151 storres
    # When the absolute value of the lower bound is < 0.
1598 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
1599 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1600 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1601 62 storres
            invScalingCoeff = 1/scalingCoeff
1602 80 storres
            return((scalingCoeff * expVar,
1603 80 storres
                    invScalingCoeff * expVar))
1604 60 storres
        else:
1605 62 storres
            scalingCoeff = \
1606 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
1607 62 storres
            scalingOffset = -3 * scalingCoeff
1608 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1609 80 storres
                    1/scalingCoeff * expVar + 3))
1610 61 storres
    else:
1611 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1612 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1613 61 storres
            scalingOffset = 0
1614 80 storres
            return((scalingCoeff * expVar,
1615 80 storres
                    1/scalingCoeff * expVar))
1616 61 storres
        else:
1617 62 storres
            scalingCoeff = \
1618 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1619 62 storres
            scalingOffset =  -3 * scalingCoeff
1620 62 storres
            #scalingOffset = 0
1621 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1622 80 storres
                    1/scalingCoeff * expVar + 3))
1623 165 storres
"""
1624 151 storres
# End slz_interval_scaling_expression
1625 61 storres
1626 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1627 72 storres
    """
1628 72 storres
    Compute the Sage version of the Taylor polynomial and it's
1629 72 storres
    companion data (interval, center...)
1630 72 storres
    The input parameter is a five elements tuple:
1631 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1632 79 storres
           real ring;
1633 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1634 79 storres
           over a real ring;
1635 72 storres
    - [2]: the interval (as Sollya range);
1636 72 storres
    - [3]: the interval center;
1637 72 storres
    - [4]: the approximation error.
1638 72 storres
1639 218 storres
    The function returns a 5 elements tuple: formed with all the
1640 72 storres
    input elements converted into their Sollya counterpart.
1641 72 storres
    """
1642 218 storres
    polynomialSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[0])
1643 218 storres
    #print "Polynomial after first conversion: ", pobyso_autoprint(polyRangeCenterErrorSo[1])
1644 218 storres
    polynomialChangedVarSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[1])
1645 60 storres
    intervalSa = \
1646 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1647 60 storres
    centerSa = \
1648 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1649 60 storres
    errorSa = \
1650 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1651 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1652 83 storres
    # End slz_interval_and_polynomial_to_sage
1653 62 storres
1654 172 storres
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None,
1655 172 storres
            targetPlusOnePrecRF = None, quasiExactRF = None):
1656 172 storres
    """
1657 172 storres
      Check if an element (argument) of the domain of function (function)
1658 172 storres
      yields a HTRN case (rounding to next) for the target precision
1659 183 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuracy).
1660 205 storres
1661 205 storres
      The strategy is:
1662 205 storres
      - compute the image at high (quasi-exact) precision;
1663 205 storres
      - round it to nearest to precision;
1664 205 storres
      - round it to exactly to (precision+1), the computed number has two
1665 205 storres
        midpoint neighbors;
1666 205 storres
      - check the distance between these neighbors and the quasi-exact value;
1667 205 storres
        - if none of them is closer than the targetAccuracy, return False,
1668 205 storres
        - else return true.
1669 205 storres
      - Powers of two are a special case when comparing the midpoint in
1670 205 storres
        the 0 direction..
1671 172 storres
    """
1672 183 storres
    ## Arguments filtering.
1673 183 storres
    ## TODO: filter the first argument for consistence.
1674 172 storres
    if targetRF is None:
1675 172 storres
        targetRF = argument.parent()
1676 172 storres
    ## Ditto for the real field holding the midpoints.
1677 172 storres
    if targetPlusOnePrecRF is None:
1678 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1679 183 storres
    ## If no quasiExactField is provided, create a high accuracy RealField.
1680 172 storres
    if quasiExactRF is None:
1681 172 storres
        quasiExactRF = RealField(1536)
1682 195 storres
    function                      = function.function(function.variables()[0])
1683 172 storres
    exactArgument                 = quasiExactRF(argument)
1684 172 storres
    quasiExactValue               = function(exactArgument)
1685 172 storres
    roundedValue                  = targetRF(quasiExactValue)
1686 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1687 172 storres
    # Upper midpoint.
1688 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1689 172 storres
    # Lower midpoint.
1690 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1691 172 storres
    binade                        = slz_compute_binade(roundedValue)
1692 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1693 172 storres
    #print "Argument:", argument
1694 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1695 174 storres
    #print "Binade:", binade
1696 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1697 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
1698 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1699 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1700 172 storres
    #print "Upper midpoint:", \
1701 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1702 172 storres
    #print "Rounded value :", \
1703 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1704 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1705 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1706 172 storres
    #print "Lower midpoint:", \
1707 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1708 205 storres
    ## Make quasiExactValue = 0 a special case to move it out of the way.
1709 205 storres
    if quasiExactValue == 0:
1710 205 storres
        return False
1711 205 storres
    ## Begining of the general case : check with the midpoint of
1712 172 storres
    #  greatest absolute value.
1713 172 storres
    if quasiExactValue > 0:
1714 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1715 172 storres
           binadeCorrectedTargetAccuracy:
1716 183 storres
            #print "Too close to the upper midpoint: ", \
1717 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1718 172 storres
            #print argument.n().str(base=16, \
1719 172 storres
            #  no_sci=False)
1720 172 storres
            #print "Lower midpoint:", \
1721 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1722 172 storres
            #print "Value         :", \
1723 183 storres
            # quasiExactValue.n(prec=200).str(base=2)
1724 172 storres
            #print "Upper midpoint:", \
1725 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1726 172 storres
            return True
1727 205 storres
    else: # quasiExactValue < 0, the 0 case has been previously filtered out.
1728 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1729 172 storres
           binadeCorrectedTargetAccuracy:
1730 172 storres
            #print "Too close to the upper midpoint: ", \
1731 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1732 172 storres
            #print argument.n().str(base=16, \
1733 172 storres
            #  no_sci=False)
1734 172 storres
            #print "Lower midpoint:", \
1735 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1736 172 storres
            #print "Value         :", \
1737 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1738 172 storres
            #print "Upper midpoint:", \
1739 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1740 172 storres
            #print
1741 172 storres
            return True
1742 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1743 172 storres
    ## For the midpoint of smaller absolute value,
1744 172 storres
    #  split cases with the powers of 2.
1745 172 storres
    if sno_abs_is_power_of_two(roundedValue):
1746 172 storres
        if quasiExactValue > 0:
1747 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1748 172 storres
               binadeCorrectedTargetAccuracy / 2:
1749 172 storres
                #print "Lower midpoint:", \
1750 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1751 172 storres
                #print "Value         :", \
1752 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1753 172 storres
                #print "Upper midpoint:", \
1754 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1755 172 storres
                #print
1756 172 storres
                return True
1757 172 storres
        else:
1758 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1759 172 storres
              binadeCorrectedTargetAccuracy / 2:
1760 172 storres
                #print "Lower midpoint:", \
1761 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1762 172 storres
                #print "Value         :",
1763 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1764 172 storres
                #print "Upper midpoint:",
1765 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1766 172 storres
                #print
1767 172 storres
                return True
1768 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1769 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
1770 172 storres
          #  smaller absolute value.
1771 172 storres
        if quasiExactValue > 0:
1772 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1773 172 storres
              binadeCorrectedTargetAccuracy:
1774 172 storres
                #print "Lower midpoint:", \
1775 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1776 172 storres
                #print "Value         :", \
1777 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1778 172 storres
                #print "Upper midpoint:", \
1779 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1780 172 storres
                #print
1781 172 storres
                return True
1782 172 storres
        else: # quasiExactValue <= 0
1783 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1784 172 storres
              binadeCorrectedTargetAccuracy:
1785 172 storres
                #print "Lower midpoint:", \
1786 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1787 172 storres
                #print "Value         :", \
1788 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1789 172 storres
                #print "Upper midpoint:", \
1790 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1791 172 storres
                #print
1792 172 storres
                return True
1793 172 storres
    #print "distance to the upper midpoint:", \
1794 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1795 172 storres
    #print "distance to the lower midpoint:", \
1796 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1797 172 storres
    return False
1798 172 storres
# End slz_is_htrn
1799 172 storres
1800 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
1801 80 storres
                                                precision,
1802 80 storres
                                                targetHardnessToRound,
1803 80 storres
                                                variable1,
1804 80 storres
                                                variable2):
1805 80 storres
    """
1806 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
1807 90 storres
     with the Coppersmith method.
1808 80 storres
    A the same time it computes :
1809 80 storres
    - 2^K (N);
1810 90 storres
    - 2^k (bound on the second variable)
1811 80 storres
    - lcm
1812 90 storres
1813 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1814 90 storres
                         variables.
1815 90 storres
    :param precision: the precision of the floating-point coefficients.
1816 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
1817 90 storres
    :param variable1: the first variable of the polynomial (an expression).
1818 90 storres
    :param variable2: the second variable of the polynomial (an expression).
1819 90 storres
1820 90 storres
    :returns: a 4 elements tuple:
1821 90 storres
                - the polynomial;
1822 91 storres
                - the modulus (N);
1823 91 storres
                - the t bound;
1824 90 storres
                - the lcm used to compute the integral coefficients and the
1825 90 storres
                  module.
1826 80 storres
    """
1827 80 storres
    # Create a new integer polynomial ring.
1828 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1829 80 storres
    # Coefficients are issued in the increasing power order.
1830 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1831 91 storres
    # Print the reversed list for debugging.
1832 179 storres
    #print
1833 179 storres
    #print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1834 94 storres
    # Build the list of number we compute the lcm of.
1835 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1836 179 storres
    #print "Coefficient denominators:", coefficientDenominators
1837 80 storres
    coefficientDenominators.append(2^precision)
1838 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
1839 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
1840 80 storres
    # Compute the expression corresponding to the new polynomial
1841 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1842 91 storres
    #print coefficientNumerators
1843 80 storres
    polynomialExpression = 0
1844 80 storres
    power = 0
1845 170 storres
    # Iterate over two lists at the same time, stop when the shorter
1846 170 storres
    # (is this case coefficientsNumerators) is
1847 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
1848 170 storres
    # of variable1.
1849 80 storres
    for numerator, denominator in \
1850 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
1851 80 storres
        multiplicator = leastCommonMultiple / denominator
1852 80 storres
        newCoefficient = numerator * multiplicator
1853 80 storres
        polynomialExpression += newCoefficient * variable1^power
1854 80 storres
        power +=1
1855 80 storres
    polynomialExpression += - variable2
1856 80 storres
    return (IP(polynomialExpression),
1857 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
1858 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1859 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1860 91 storres
            leastCommonMultiple) # If we want to make test computations.
1861 80 storres
1862 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1863 79 storres
1864 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
1865 79 storres
                                          precision):
1866 79 storres
    """
1867 79 storres
    Makes a variable substitution into the input polynomial so that the output
1868 79 storres
    polynomial can take integer arguments.
1869 79 storres
    All variables of the input polynomial "have precision p". That is to say
1870 103 storres
    that they are rationals with denominator == 2^(precision - 1):
1871 103 storres
    x = y/2^(precision - 1).
1872 79 storres
    We "incorporate" these denominators into the coefficients with,
1873 79 storres
    respectively, the "right" power.
1874 79 storres
    """
1875 79 storres
    polynomialField = ratPolyOfRat.parent()
1876 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
1877 91 storres
    #print "The polynomial field is:", polynomialField
1878 79 storres
    return \
1879 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1880 79 storres
                                   polynomialVariable/2^(precision-1)}))
1881 79 storres
1882 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1883 79 storres
1884 177 storres
def slz_reduce_and_test_base(matrixToReduce,
1885 177 storres
                             nAtAlpha,
1886 177 storres
                             monomialsCountSqrt):
1887 177 storres
    """
1888 177 storres
    Reduces the basis, tests the Coppersmith condition and returns
1889 177 storres
    a list of rows that comply with the condition.
1890 177 storres
    """
1891 177 storres
    ccComplientRowsList = []
1892 177 storres
    reducedMatrix = matrixToReduce.LLL(None)
1893 177 storres
    if not reducedMatrix.is_LLL_reduced():
1894 177 storres
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
1895 177 storres
    else:
1896 177 storres
        print "reducedMatrix is actually reduced."
1897 177 storres
    print "N^alpha:", nAtAlpha.n()
1898 177 storres
    rowIndex = 0
1899 177 storres
    for row in reducedMatrix.rows():
1900 177 storres
        l2Norm = row.norm(2)
1901 177 storres
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
1902 177 storres
                monomialsCountSqrt.n(), ". Is vector OK?",
1903 177 storres
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
1904 177 storres
            ccComplientRowsList.append(row)
1905 177 storres
            print "True"
1906 177 storres
        else:
1907 177 storres
            print "False"
1908 177 storres
    # End for
1909 177 storres
    return ccComplientRowsList
1910 177 storres
# End slz_reduce_and_test_base
1911 115 storres
1912 205 storres
def slz_resultant(poly1, poly2, elimVar):
1913 205 storres
    """
1914 205 storres
    Compute the resultant for two polynomials for a given variable
1915 205 storres
    and return the (poly1, poly2, resultant) if the resultant
1916 205 storres
    is not 0.
1917 205 storres
    Return () otherwise.
1918 205 storres
    """
1919 205 storres
    polynomialRing0    = poly1.parent()
1920 205 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1921 213 storres
    if resultantInElimVar is None:
1922 213 storres
        return None
1923 205 storres
    if resultantInElimVar.is_zero():
1924 205 storres
        return None
1925 205 storres
    else:
1926 205 storres
        return resultantInElimVar
1927 205 storres
# End slz_resultant.
1928 205 storres
#
1929 177 storres
def slz_resultant_tuple(poly1, poly2, elimVar):
1930 179 storres
    """
1931 179 storres
    Compute the resultant for two polynomials for a given variable
1932 179 storres
    and return the (poly1, poly2, resultant) if the resultant
1933 180 storres
    is not 0.
1934 179 storres
    Return () otherwise.
1935 179 storres
    """
1936 181 storres
    polynomialRing0    = poly1.parent()
1937 177 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1938 180 storres
    if resultantInElimVar.is_zero():
1939 177 storres
        return ()
1940 177 storres
    else:
1941 177 storres
        return (poly1, poly2, resultantInElimVar)
1942 177 storres
# End slz_resultant_tuple.
1943 177 storres
#
1944 87 storres
print "\t...sageSLZ loaded"