Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (88,34 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
    sollyaPrecChanged = False
597 218 storres
    (sollyaPrecSo, sollyaPrecSa) = pobyso_get_prec_so_so_sa()
598 218 storres
    if precSa is None:
599 218 storres
        precSa = ceil((RR('1.5') * abs(RR(approxAccurSa).log2())) / 64) * 64
600 218 storres
        #print "Computed internal precision:", precSa
601 218 storres
        if precSa < 192:
602 218 storres
            precSa = 192
603 218 storres
    if precSa != sollyaPrecSa:
604 218 storres
        precSo = pobyso_constant_from_int_sa_so(precSa)
605 218 storres
        pobyso_set_prec_so_so(precSo)
606 218 storres
        sollya_lib_clear_obj(precSo)
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 218 storres
                pobyso_set_prec_so_so(sollyaPrecSo)
659 218 storres
                sollya_lib_clear_obj(sollyaPrecSo)
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 218 storres
        pobyso_set_prec_so_so(sollyaPrecSo)
681 218 storres
        sollya_lib_clear_obj(sollyaPrecSo)
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 225 storres
    sollyaPrecChangedSa = False
713 225 storres
    if sollyaPrecSa is None:
714 225 storres
        sollyaPrecSa = pobyso_get_prec_so_sa()
715 219 storres
    else:
716 225 storres
        initialSollyaPrecSa = pobyso_get_prec_so_sa()
717 225 storres
        if sollyaPrecSa != initialSollyaPrecSa:
718 225 storres
            initialSollyaPrecSo = pobyso_get_prec_so()
719 225 storres
            pobyso_set_prec_sa_so(sollyaPrecSa)
720 225 storres
            sollyaPrecChangedSa = True
721 225 storres
    ## Other initializations and data recovery.
722 219 storres
    RRR = lowerBoundSa.parent()
723 219 storres
    intervalShrinkConstFactorSa = RRR('0.9')
724 219 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
725 219 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
726 219 storres
    currentUpperBoundSa = upperBoundSa
727 219 storres
    currentLowerBoundSa = lowerBoundSa
728 219 storres
    # What we want here is the polynomial without the variable change,
729 219 storres
    # since our actual variable will be x-intervalCenter defined over the
730 219 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
731 219 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
732 219 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
733 219 storres
                                                    currentRangeSo,
734 219 storres
                                                    absoluteErrorTypeSo)
735 219 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
736 219 storres
    while maxErrorSa > approxAccurSa:
737 219 storres
        print "++Approximation error:", maxErrorSa.n()
738 219 storres
        sollya_lib_clear_obj(polySo)
739 219 storres
        sollya_lib_clear_obj(intervalCenterSo)
740 219 storres
        sollya_lib_clear_obj(maxErrorSo)
741 219 storres
        # Very empirical shrinking factor.
742 219 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
743 219 storres
        print "Shrink factor:", \
744 219 storres
              shrinkFactorSa.n(), \
745 219 storres
              intervalShrinkConstFactorSa
746 219 storres
        print
747 219 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
748 219 storres
        #print "Error ratio: ", errorRatioSa
749 219 storres
        # Make sure interval shrinks.
750 219 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
751 219 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
752 219 storres
            #print "Fixed"
753 219 storres
        else:
754 219 storres
            actualShrinkFactorSa = shrinkFactorSa
755 219 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
756 219 storres
            #print shrinkFactorSa, maxErrorSa
757 219 storres
        #print "Shrink factor", actualShrinkFactorSa
758 219 storres
        currentUpperBoundSa = currentLowerBoundSa + \
759 219 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
760 219 storres
                                actualShrinkFactorSa
761 219 storres
        #print "Current upper bound:", currentUpperBoundSa
762 219 storres
        sollya_lib_clear_obj(currentRangeSo)
763 219 storres
        # Check what is left with the bounds.
764 219 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
765 219 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
766 219 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
767 219 storres
            print "Can't find an interval."
768 219 storres
            print "Use either or both a higher polynomial degree or a higher",
769 219 storres
            print "internal precision."
770 219 storres
            print "Aborting!"
771 225 storres
            if sollyaPrecChangedSa:
772 225 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
773 225 storres
                sollya_lib_clear_obj(initialSollyaPrecSo)
774 219 storres
            return None
775 219 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
776 219 storres
                                                      currentUpperBoundSa)
777 219 storres
        # print "New interval:",
778 219 storres
        # pobyso_autoprint(currentRangeSo)
779 219 storres
        #print "Second Taylor expansion call."
780 219 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
781 219 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
782 219 storres
                                                        currentRangeSo,
783 219 storres
                                                        absoluteErrorTypeSo)
784 219 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
785 219 storres
        #print "Max errorSo:",
786 219 storres
        #pobyso_autoprint(maxErrorSo)
787 219 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
788 219 storres
        #print "Max errorSa:", maxErrorSa
789 219 storres
        #print "Sollya prec:",
790 219 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
791 219 storres
    # End while
792 219 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
793 219 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
794 219 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
795 219 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
796 219 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
797 219 storres
    if debug:
798 219 storres
        print "About to call polynomial rounding with:"
799 219 storres
        print "polySo: ",           ; pobyso_autoprint(polySo)
800 219 storres
        print "functionSo: ",       ; pobyso_autoprint(functionSo)
801 219 storres
        print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
802 219 storres
        print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
803 219 storres
        print "itpSo: ",            ; pobyso_autoprint(itpSo)
804 219 storres
        print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
805 219 storres
        print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
806 219 storres
        print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
807 224 storres
    """
808 224 storres
    # Naive rounding.
809 219 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
810 219 storres
    pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
811 219 storres
                                                           functionSo,
812 219 storres
                                                           intervalCenterSo,
813 219 storres
                                                           currentRangeSo,
814 219 storres
                                                           itpSo,
815 219 storres
                                                           ftpSo,
816 219 storres
                                                           maxPrecSo,
817 219 storres
                                                           approxAccurSo)
818 224 storres
    """
819 224 storres
    # Proved rounding.
820 224 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
821 224 storres
        pobyso_round_coefficients_progressive_so_so(polySo,
822 224 storres
                                                    functionSo,
823 224 storres
                                                    maxPrecSo,
824 224 storres
                                                    currentRangeSo,
825 224 storres
                                                    intervalCenterSo,
826 224 storres
                                                    maxErrorSo,
827 224 storres
                                                    approxAccurSo,
828 224 storres
                                                    debug=False)
829 224 storres
    #### Comment out the two next lines when polynomial rounding is activated.
830 224 storres
    #roundedPolySo = sollya_lib_copy_obj(polySo)
831 224 storres
    #roundedPolyMaxErrSo =  sollya_lib_copy_obj(maxErrorSo)
832 219 storres
    sollya_lib_clear_obj(polySo)
833 219 storres
    sollya_lib_clear_obj(maxErrorSo)
834 219 storres
    sollya_lib_clear_obj(itpSo)
835 219 storres
    sollya_lib_clear_obj(ftpSo)
836 219 storres
    sollya_lib_clear_obj(approxAccurSo)
837 225 storres
    if sollyaPrecChangedSa:
838 225 storres
        pobyso_set_prec_so_so(initialSollyaPrecSa)
839 225 storres
        sollya_lib_clear_obj(initialSollyaPrecSa)
840 219 storres
    if debug:
841 219 storres
        print "1: ", ; pobyso_autoprint(roundedPolySo)
842 219 storres
        print "2: ", ; pobyso_autoprint(currentRangeSo)
843 219 storres
        print "3: ", ; pobyso_autoprint(intervalCenterSo)
844 219 storres
        print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
845 219 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
846 219 storres
# End slz_compute_polynomial_and_interval_01
847 219 storres
848 219 storres
def slz_compute_polynomial_and_interval_02(functionSo, degreeSo, lowerBoundSa,
849 219 storres
                                        upperBoundSa, approxAccurSa,
850 218 storres
                                        sollyaPrecSa=None):
851 218 storres
    """
852 218 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
853 218 storres
    a polynomial that approximates the function on a an interval starting
854 218 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
855 218 storres
    approximates with the expected precision.
856 218 storres
    The interval upper bound is lowered until the expected approximation
857 218 storres
    precision is reached.
858 218 storres
    The polynomial, the bounds, the center of the interval and the error
859 218 storres
    are returned.
860 218 storres
    OUTPUT:
861 218 storres
    A tuple made of 4 Sollya objects:
862 218 storres
    - a polynomial;
863 218 storres
    - an range (an interval, not in the sense of number given as an interval);
864 218 storres
    - the center of the interval;
865 218 storres
    - the maximum error in the approximation of the input functionSo by the
866 218 storres
      output polynomial ; this error <= approxAccurSaS.
867 218 storres
868 218 storres
    """
869 218 storres
    print"In slz_compute_polynomial_and_interval..."
870 218 storres
    ## Superficial argument check.
871 218 storres
    if lowerBoundSa > upperBoundSa:
872 218 storres
        return None
873 218 storres
    ## Change Sollya precision, if requested.
874 218 storres
    if not sollyaPrecSa is None:
875 218 storres
        sollyaPrecSo = pobyso_get_prec_so()
876 218 storres
        pobyso_set_prec_sa_so(sollyaPrecSa)
877 218 storres
    else:
878 218 storres
        sollyaPrecSa = pobyso_get_prec_so_sa()
879 218 storres
        sollyaPrecSo = None
880 218 storres
    RRR = lowerBoundSa.parent()
881 218 storres
    intervalShrinkConstFactorSa = RRR('0.9')
882 218 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
883 218 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
884 218 storres
    currentUpperBoundSa = upperBoundSa
885 218 storres
    currentLowerBoundSa = lowerBoundSa
886 218 storres
    # What we want here is the polynomial without the variable change,
887 218 storres
    # since our actual variable will be x-intervalCenter defined over the
888 218 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
889 218 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
890 218 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
891 218 storres
                                                    currentRangeSo,
892 218 storres
                                                    absoluteErrorTypeSo)
893 218 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
894 218 storres
    while maxErrorSa > approxAccurSa:
895 218 storres
        print "++Approximation error:", maxErrorSa.n()
896 218 storres
        sollya_lib_clear_obj(polySo)
897 218 storres
        sollya_lib_clear_obj(intervalCenterSo)
898 218 storres
        sollya_lib_clear_obj(maxErrorSo)
899 218 storres
        # Very empirical shrinking factor.
900 218 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
901 218 storres
        print "Shrink factor:", \
902 218 storres
              shrinkFactorSa.n(), \
903 218 storres
              intervalShrinkConstFactorSa
904 218 storres
        print
905 218 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
906 218 storres
        #print "Error ratio: ", errorRatioSa
907 218 storres
        # Make sure interval shrinks.
908 218 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
909 218 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
910 218 storres
            #print "Fixed"
911 218 storres
        else:
912 218 storres
            actualShrinkFactorSa = shrinkFactorSa
913 218 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
914 218 storres
            #print shrinkFactorSa, maxErrorSa
915 218 storres
        #print "Shrink factor", actualShrinkFactorSa
916 218 storres
        currentUpperBoundSa = currentLowerBoundSa + \
917 218 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
918 218 storres
                                actualShrinkFactorSa
919 218 storres
        #print "Current upper bound:", currentUpperBoundSa
920 218 storres
        sollya_lib_clear_obj(currentRangeSo)
921 218 storres
        # Check what is left with the bounds.
922 218 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
923 218 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
924 218 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
925 218 storres
            print "Can't find an interval."
926 218 storres
            print "Use either or both a higher polynomial degree or a higher",
927 218 storres
            print "internal precision."
928 218 storres
            print "Aborting!"
929 218 storres
            if not sollyaPrecSo is None:
930 218 storres
                pobyso_set_prec_so_so(sollyaPrecSo)
931 218 storres
                sollya_lib_clear_obj(sollyaPrecSo)
932 218 storres
            return None
933 218 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
934 218 storres
                                                      currentUpperBoundSa)
935 218 storres
        # print "New interval:",
936 218 storres
        # pobyso_autoprint(currentRangeSo)
937 218 storres
        #print "Second Taylor expansion call."
938 218 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
939 218 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
940 218 storres
                                                        currentRangeSo,
941 218 storres
                                                        absoluteErrorTypeSo)
942 218 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
943 218 storres
        #print "Max errorSo:",
944 218 storres
        #pobyso_autoprint(maxErrorSo)
945 218 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
946 218 storres
        #print "Max errorSa:", maxErrorSa
947 218 storres
        #print "Sollya prec:",
948 218 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
949 218 storres
    # End while
950 218 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
951 218 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
952 218 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
953 218 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
954 218 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
955 218 storres
    print "About to call polynomial rounding with:"
956 218 storres
    print "polySo: ",           ; pobyso_autoprint(polySo)
957 218 storres
    print "functionSo: ",       ; pobyso_autoprint(functionSo)
958 218 storres
    print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
959 218 storres
    print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
960 218 storres
    print "itpSo: ",            ; pobyso_autoprint(itpSo)
961 218 storres
    print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
962 218 storres
    print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
963 218 storres
    print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
964 218 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
965 218 storres
    pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
966 218 storres
                                                           functionSo,
967 218 storres
                                                           intervalCenterSo,
968 218 storres
                                                           currentRangeSo,
969 218 storres
                                                           itpSo,
970 218 storres
                                                           ftpSo,
971 218 storres
                                                           maxPrecSo,
972 218 storres
                                                           approxAccurSo)
973 218 storres
974 218 storres
    sollya_lib_clear_obj(polySo)
975 218 storres
    sollya_lib_clear_obj(maxErrorSo)
976 218 storres
    sollya_lib_clear_obj(itpSo)
977 218 storres
    sollya_lib_clear_obj(ftpSo)
978 218 storres
    sollya_lib_clear_obj(approxAccurSo)
979 218 storres
    if not sollyaPrecSo is None:
980 218 storres
        pobyso_set_prec_so_so(sollyaPrecSo)
981 218 storres
        sollya_lib_clear_obj(sollyaPrecSo)
982 218 storres
    print "1: ", ; pobyso_autoprint(roundedPolySo)
983 218 storres
    print "2: ", ; pobyso_autoprint(currentRangeSo)
984 218 storres
    print "3: ", ; pobyso_autoprint(intervalCenterSo)
985 218 storres
    print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
986 218 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
987 219 storres
# End slz_compute_polynomial_and_interval_02
988 218 storres
989 122 storres
def slz_compute_reduced_polynomial(matrixRow,
990 98 storres
                                    knownMonomials,
991 106 storres
                                    var1,
992 98 storres
                                    var1Bound,
993 106 storres
                                    var2,
994 99 storres
                                    var2Bound):
995 98 storres
    """
996 125 storres
    Compute a polynomial from a single reduced matrix row.
997 122 storres
    This function was introduced in order to avoid the computation of the
998 125 storres
    all the polynomials  from the full matrix (even those built from rows
999 125 storres
    that do no verify the Coppersmith condition) as this may involves
1000 152 storres
    expensive operations over (large) integers.
1001 122 storres
    """
1002 122 storres
    ## Check arguments.
1003 122 storres
    if len(knownMonomials) == 0:
1004 122 storres
        return None
1005 122 storres
    # varNounds can be zero since 0^0 returns 1.
1006 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
1007 122 storres
        return None
1008 122 storres
    ## Initialisations.
1009 122 storres
    polynomialRing = knownMonomials[0].parent()
1010 122 storres
    currentPolynomial = polynomialRing(0)
1011 123 storres
    # TODO: use zip instead of indices.
1012 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
1013 122 storres
        currentCoefficient = matrixRow[colIndex]
1014 122 storres
        if currentCoefficient != 0:
1015 122 storres
            #print "Current coefficient:", currentCoefficient
1016 122 storres
            currentMonomial = knownMonomials[colIndex]
1017 122 storres
            #print "Monomial as multivariate polynomial:", \
1018 122 storres
            #currentMonomial, type(currentMonomial)
1019 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
1020 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
1021 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
1022 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
1023 122 storres
            if degreeInVar1 > 0:
1024 122 storres
                currentCoefficient = \
1025 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
1026 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
1027 122 storres
                #print "Current coefficient(1)", currentCoefficient
1028 122 storres
            if degreeInVar2 > 0:
1029 122 storres
                currentCoefficient = \
1030 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
1031 122 storres
                #print "Current coefficient(2)", currentCoefficient
1032 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
1033 122 storres
            #                                    currentMonomial)
1034 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
1035 122 storres
            #print "Current polynomial:", currentPolynomial
1036 122 storres
        # End if
1037 122 storres
    # End for colIndex.
1038 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
1039 122 storres
    return(currentPolynomial)
1040 122 storres
# End slz_compute_reduced_polynomial
1041 122 storres
#
1042 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
1043 122 storres
                                        knownMonomials,
1044 122 storres
                                        var1,
1045 122 storres
                                        var1Bound,
1046 122 storres
                                        var2,
1047 122 storres
                                        var2Bound):
1048 122 storres
    """
1049 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
1050 122 storres
    """
1051 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
1052 122 storres
                                                knownMonomials,
1053 122 storres
                                                var1,
1054 122 storres
                                                var1Bound,
1055 122 storres
                                                var2,
1056 122 storres
                                                var2Bound)
1057 122 storres
    )
1058 177 storres
#
1059 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
1060 152 storres
                                         knownMonomials,
1061 152 storres
                                         var1,
1062 152 storres
                                         var1Bound,
1063 152 storres
                                         var2,
1064 152 storres
                                         var2Bound):
1065 122 storres
    """
1066 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
1067 98 storres
    from the bounds of each variable, compute the corresponding polynomials
1068 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1069 99 storres
1070 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1071 172 storres
    They set the polynomial type of the output polynomials in list.
1072 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
1073 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1074 152 storres
                           build the polynomials;
1075 152 storres
    @param var1:           the first variable (of the "right" type);
1076 152 storres
    @param var1Bound:      the first variable bound;
1077 152 storres
    @param var2:           the second variable (of the "right" type);
1078 152 storres
    @param var2Bound:      the second variable bound.
1079 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
1080 152 storres
             and scaled down with the bounds
1081 98 storres
    """
1082 99 storres
1083 98 storres
    # TODO: check input arguments.
1084 98 storres
    reducedPolynomials = []
1085 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1086 98 storres
    for matrixRow in reducedMatrix.rows():
1087 102 storres
        currentPolynomial = 0
1088 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
1089 98 storres
            currentCoefficient = matrixRow[colIndex]
1090 106 storres
            if currentCoefficient != 0:
1091 106 storres
                #print "Current coefficient:", currentCoefficient
1092 106 storres
                currentMonomial = knownMonomials[colIndex]
1093 106 storres
                parentRing = currentMonomial.parent()
1094 106 storres
                #print "Monomial as multivariate polynomial:", \
1095 106 storres
                #currentMonomial, type(currentMonomial)
1096 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1097 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
1098 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1099 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
1100 106 storres
                if degreeInVar1 > 0:
1101 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1102 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1103 106 storres
                    #print "Current coefficient(1)", currentCoefficient
1104 106 storres
                if degreeInVar2 > 0:
1105 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1106 106 storres
                    #print "Current coefficient(2)", currentCoefficient
1107 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1108 106 storres
                #                                    currentMonomial)
1109 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1110 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1111 168 storres
                    #print "!!!! constant term !!!!"
1112 106 storres
                #print "Current polynomial:", currentPolynomial
1113 106 storres
            # End if
1114 106 storres
        # End for colIndex.
1115 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1116 99 storres
        reducedPolynomials.append(currentPolynomial)
1117 98 storres
    return reducedPolynomials
1118 177 storres
# End slz_compute_reduced_polynomials_list.
1119 98 storres
1120 177 storres
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
1121 177 storres
                                                   knownMonomials,
1122 177 storres
                                                   var1,
1123 177 storres
                                                   var1Bound,
1124 177 storres
                                                   var2,
1125 177 storres
                                                   var2Bound):
1126 177 storres
    """
1127 177 storres
    From a list of rows, holding the coefficients, from a monomials list,
1128 177 storres
    from the bounds of each variable, compute the corresponding polynomials
1129 177 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1130 177 storres
1131 177 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1132 177 storres
    They set the polynomial type of the output polynomials in list.
1133 177 storres
    @param rowsList:       the reduced matrix as output from LLL;
1134 177 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1135 177 storres
                           build the polynomials;
1136 177 storres
    @param var1:           the first variable (of the "right" type);
1137 177 storres
    @param var1Bound:      the first variable bound;
1138 177 storres
    @param var2:           the second variable (of the "right" type);
1139 177 storres
    @param var2Bound:      the second variable bound.
1140 177 storres
    @return: a list of polynomials obtained with the reduced coefficients
1141 177 storres
             and scaled down with the bounds
1142 177 storres
    """
1143 177 storres
1144 177 storres
    # TODO: check input arguments.
1145 177 storres
    reducedPolynomials = []
1146 177 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1147 177 storres
    for matrixRow in rowsList:
1148 177 storres
        currentPolynomial = 0
1149 177 storres
        for colIndex in xrange(0, len(knownMonomials)):
1150 177 storres
            currentCoefficient = matrixRow[colIndex]
1151 177 storres
            if currentCoefficient != 0:
1152 177 storres
                #print "Current coefficient:", currentCoefficient
1153 177 storres
                currentMonomial = knownMonomials[colIndex]
1154 177 storres
                parentRing = currentMonomial.parent()
1155 177 storres
                #print "Monomial as multivariate polynomial:", \
1156 177 storres
                #currentMonomial, type(currentMonomial)
1157 177 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1158 177 storres
                #print "Degree in var", var1, ":", degreeInVar1
1159 177 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1160 177 storres
                #print "Degree in var", var2, ":", degreeInVar2
1161 177 storres
                if degreeInVar1 > 0:
1162 177 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1163 177 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1164 177 storres
                    #print "Current coefficient(1)", currentCoefficient
1165 177 storres
                if degreeInVar2 > 0:
1166 177 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1167 177 storres
                    #print "Current coefficient(2)", currentCoefficient
1168 177 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1169 177 storres
                #                                    currentMonomial)
1170 177 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1171 177 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1172 177 storres
                    #print "!!!! constant term !!!!"
1173 177 storres
                #print "Current polynomial:", currentPolynomial
1174 177 storres
            # End if
1175 177 storres
        # End for colIndex.
1176 177 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1177 177 storres
        reducedPolynomials.append(currentPolynomial)
1178 177 storres
    return reducedPolynomials
1179 177 storres
# End slz_compute_reduced_polynomials_list_from_rows.
1180 177 storres
#
1181 114 storres
def slz_compute_scaled_function(functionSa,
1182 114 storres
                                lowerBoundSa,
1183 114 storres
                                upperBoundSa,
1184 156 storres
                                floatingPointPrecSa,
1185 156 storres
                                debug=False):
1186 72 storres
    """
1187 72 storres
    From a function, compute the scaled function whose domain
1188 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
1189 72 storres
    Return a tuple:
1190 72 storres
    [0]: the scaled function
1191 72 storres
    [1]: the scaled domain lower bound
1192 72 storres
    [2]: the scaled domain upper bound
1193 72 storres
    [3]: the scaled image lower bound
1194 72 storres
    [4]: the scaled image upper bound
1195 72 storres
    """
1196 177 storres
    ## The variable can be called anything.
1197 80 storres
    x = functionSa.variables()[0]
1198 72 storres
    # Scalling the domain -> [1,2[.
1199 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
1200 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
1201 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
1202 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
1203 156 storres
    if debug:
1204 156 storres
        print "domainScalingExpression for argument :", \
1205 156 storres
        invDomainScalingExpressionSa
1206 190 storres
        print "function: ", functionSa
1207 190 storres
    ff = functionSa.subs({x : domainScalingExpressionSa})
1208 190 storres
    ## Bless expression as a function.
1209 190 storres
    ff = ff.function(x)
1210 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
1211 177 storres
    #domainScalingFunction(x) = invDomainScalingExpressionSa
1212 177 storres
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
1213 151 storres
    scaledLowerBoundSa = \
1214 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
1215 151 storres
    scaledUpperBoundSa = \
1216 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
1217 156 storres
    if debug:
1218 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
1219 156 storres
              scaledUpperBoundSa
1220 72 storres
    #
1221 72 storres
    # Scalling the image -> [1,2[.
1222 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
1223 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
1224 72 storres
    if flbSa <= fubSa: # Increasing
1225 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
1226 72 storres
    else: # Decreasing
1227 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
1228 156 storres
    if debug:
1229 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
1230 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
1231 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
1232 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
1233 156 storres
    if debug:
1234 156 storres
        print "imageScalingExpression for argument :", \
1235 156 storres
              invImageScalingExpressionSa
1236 72 storres
    iis = invImageScalingExpressionSa.function(x)
1237 72 storres
    fff = iis.subs({x:ff})
1238 156 storres
    if debug:
1239 156 storres
        print "fff:", fff,
1240 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
1241 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
1242 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
1243 151 storres
# End slz_compute_scaled_function
1244 72 storres
1245 179 storres
def slz_fix_bounds_for_binades(lowerBound,
1246 179 storres
                               upperBound,
1247 190 storres
                               func = None,
1248 179 storres
                               domainDirection = -1,
1249 179 storres
                               imageDirection  = -1):
1250 179 storres
    """
1251 179 storres
    Assuming the function is increasing or decreasing over the
1252 179 storres
    [lowerBound, upperBound] interval, return a lower bound lb and
1253 179 storres
    an upper bound ub such that:
1254 179 storres
    - lb and ub belong to the same binade;
1255 179 storres
    - func(lb) and func(ub) belong to the same binade.
1256 179 storres
    domainDirection indicate how bounds move to fit into the same binade:
1257 179 storres
    - a negative value move the upper bound down;
1258 179 storres
    - a positive value move the lower bound up.
1259 179 storres
    imageDirection indicate how bounds move in order to have their image
1260 179 storres
    fit into the same binade, variation of the function is also condidered.
1261 179 storres
    For an increasing function:
1262 179 storres
    - negative value moves the upper bound down (and its image value as well);
1263 179 storres
    - a positive values moves the lower bound up (and its image value as well);
1264 179 storres
    For a decreasing function it is the other way round.
1265 179 storres
    """
1266 179 storres
    ## Arguments check
1267 179 storres
    if lowerBound > upperBound:
1268 179 storres
        return None
1269 190 storres
    if lowerBound == upperBound:
1270 190 storres
        return (lowerBound, upperBound)
1271 179 storres
    if func is None:
1272 179 storres
        return None
1273 179 storres
    #
1274 179 storres
    #varFunc = func.variables()[0]
1275 179 storres
    lb = lowerBound
1276 179 storres
    ub = upperBound
1277 179 storres
    lbBinade = slz_compute_binade(lb)
1278 179 storres
    ubBinade = slz_compute_binade(ub)
1279 179 storres
    ## Domain binade.
1280 179 storres
    while lbBinade != ubBinade:
1281 179 storres
        newIntervalWidth = (ub - lb) / 2
1282 179 storres
        if domainDirection < 0:
1283 179 storres
            ub = lb + newIntervalWidth
1284 179 storres
            ubBinade = slz_compute_binade(ub)
1285 179 storres
        else:
1286 179 storres
            lb = lb + newIntervalWidth
1287 179 storres
            lbBinade = slz_compute_binade(lb)
1288 179 storres
    ## Image binade.
1289 179 storres
    if lb == ub:
1290 179 storres
        return (lb, ub)
1291 179 storres
    lbImg = func(lb)
1292 179 storres
    ubImg = func(ub)
1293 179 storres
    funcIsInc = (ubImg >= lbImg)
1294 179 storres
    lbImgBinade = slz_compute_binade(lbImg)
1295 179 storres
    ubImgBinade = slz_compute_binade(ubImg)
1296 179 storres
    while lbImgBinade != ubImgBinade:
1297 179 storres
        newIntervalWidth = (ub - lb) / 2
1298 179 storres
        if imageDirection < 0:
1299 179 storres
            if funcIsInc:
1300 179 storres
                ub = lb + newIntervalWidth
1301 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1302 179 storres
                #print ubImgBinade
1303 179 storres
            else:
1304 179 storres
                lb = lb + newIntervalWidth
1305 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
1306 179 storres
                #print lbImgBinade
1307 179 storres
        else:
1308 179 storres
            if funcIsInc:
1309 179 storres
                lb = lb + newIntervalWidth
1310 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
1311 179 storres
                #print lbImgBinade
1312 179 storres
            else:
1313 179 storres
                ub = lb + newIntervalWidth
1314 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1315 179 storres
                #print ubImgBinade
1316 179 storres
    # End while lbImgBinade != ubImgBinade:
1317 179 storres
    return (lb, ub)
1318 179 storres
# End slz_fix_bounds_for_binades.
1319 179 storres
1320 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
1321 79 storres
    # Create a polynomial over the rationals.
1322 179 storres
    ratPolynomialRing = QQ[str(polyOfFloat.variables()[0])]
1323 179 storres
    return(ratPolynomialRing(polyOfFloat))
1324 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1325 81 storres
1326 188 storres
def slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(polyOfFloat):
1327 188 storres
    """
1328 188 storres
     Create a polynomial over the rationals where all denominators are
1329 188 storres
     powers of two.
1330 188 storres
    """
1331 188 storres
    polyVariable = polyOfFloat.variables()[0]
1332 188 storres
    RPR = QQ[str(polyVariable)]
1333 188 storres
    polyCoeffs      = polyOfFloat.coefficients()
1334 188 storres
    #print polyCoeffs
1335 188 storres
    polyExponents   = polyOfFloat.exponents()
1336 188 storres
    #print polyExponents
1337 188 storres
    polyDenomPtwoCoeffs = []
1338 188 storres
    for coeff in polyCoeffs:
1339 188 storres
        polyDenomPtwoCoeffs.append(sno_float_to_rat_pow_of_two_denom(coeff))
1340 188 storres
        #print "Converted coefficient:", sno_float_to_rat_pow_of_two_denom(coeff),
1341 188 storres
        #print type(sno_float_to_rat_pow_of_two_denom(coeff))
1342 188 storres
    ratPoly = RPR(0)
1343 188 storres
    #print type(ratPoly)
1344 188 storres
    ## !!! CAUTION !!! Do not use the RPR(coeff * polyVariagle^exponent)
1345 188 storres
    #  The coefficient becomes plainly wrong when exponent == 0.
1346 188 storres
    #  No clue as to why.
1347 188 storres
    for coeff, exponent in zip(polyDenomPtwoCoeffs, polyExponents):
1348 188 storres
        ratPoly += coeff * RPR(polyVariable^exponent)
1349 188 storres
    return ratPoly
1350 188 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1351 188 storres
1352 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
1353 63 storres
                                      lowerBoundSa,
1354 60 storres
                                      upperBoundSa, floatingPointPrecSa,
1355 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
1356 60 storres
    """
1357 60 storres
    Under the assumption that:
1358 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
1359 60 storres
    - lowerBound and upperBound belong to the same binade.
1360 60 storres
    from a:
1361 60 storres
    - function;
1362 60 storres
    - a degree
1363 60 storres
    - a pair of bounds;
1364 60 storres
    - the floating-point precision we work on;
1365 60 storres
    - the internal Sollya precision;
1366 64 storres
    - the requested approximation error
1367 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
1368 61 storres
    It return a list of tuples, each made of:
1369 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
1370 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
1371 61 storres
    - the approximation interval;
1372 72 storres
    - the center, x0, of the interval;
1373 61 storres
    - the corresponding approximation error.
1374 100 storres
    TODO: fix endless looping for some parameters sets.
1375 60 storres
    """
1376 120 storres
    resultArray = []
1377 101 storres
    # Set Sollya to the necessary internal precision.
1378 120 storres
    precChangedSa = False
1379 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
1380 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
1381 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
1382 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
1383 120 storres
        precChangedSa = True
1384 101 storres
    #
1385 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
1386 101 storres
    # Scaled function: [1=,2] -> [1,2].
1387 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
1388 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
1389 115 storres
                slz_compute_scaled_function(functionSa,                       \
1390 115 storres
                                            lowerBoundSa,                     \
1391 115 storres
                                            upperBoundSa,                     \
1392 80 storres
                                            floatingPointPrecSa)
1393 166 storres
    # In case bounds were in the negative real one may need to
1394 166 storres
    # switch scaled bounds.
1395 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
1396 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
1397 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
1398 166 storres
        #print "Switching!"
1399 218 storres
    print "Approximation accuracy: ", RR(approxAccurSa)
1400 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
1401 159 storres
    functionSo = \
1402 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
1403 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
1404 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
1405 61 storres
                                                  scaledUpperBoundSa)
1406 176 storres
1407 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
1408 60 storres
                                              upperBoundSa.parent().precision()))
1409 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
1410 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
1411 176 storres
    while True:
1412 176 storres
        ## Compute the first Taylor expansion.
1413 176 storres
        print "Computing a Taylor expansion..."
1414 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
1415 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
1416 176 storres
                                        currentScaledLowerBoundSa,
1417 176 storres
                                        currentScaledUpperBoundSa,
1418 218 storres
                                        approxAccurSa, internalSollyaPrecSa)
1419 176 storres
        print "...done."
1420 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
1421 176 storres
        #  This value goes to the first variable: polySo. Other variables are
1422 176 storres
        #  not assigned and should not be tested.
1423 176 storres
        if polySo is None:
1424 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
1425 176 storres
            if precChangedSa:
1426 176 storres
                pobyso_set_prec_so_so(currentSollyaPrecSo)
1427 176 storres
                sollya_lib_clear_obj(currentSollyaPrecSo)
1428 176 storres
            sollya_lib_clear_obj(functionSo)
1429 176 storres
            sollya_lib_clear_obj(degreeSo)
1430 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1431 176 storres
            return None
1432 176 storres
        ## Add to the result array.
1433 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
1434 176 storres
        changeVarExpressionSo = \
1435 176 storres
            sollya_lib_build_function_sub( \
1436 176 storres
                              sollya_lib_build_function_free_variable(),
1437 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
1438 176 storres
        polyVarChangedSo = \
1439 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
1440 176 storres
        #### Get rid of the variable change Sollya stuff.
1441 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
1442 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
1443 101 storres
                            intervalCenterSo, maxErrorSo))
1444 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
1445 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1446 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
1447 176 storres
        # If the error and interval are OK a the first try, just return.
1448 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
1449 218 storres
            (errorSa <= approxAccurSa):
1450 176 storres
            if precChangedSa:
1451 176 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
1452 176 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
1453 176 storres
            sollya_lib_clear_obj(functionSo)
1454 176 storres
            sollya_lib_clear_obj(degreeSo)
1455 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1456 101 storres
            #print "Approximation error:", errorSa
1457 176 storres
            return resultArray
1458 176 storres
        ## The returned interval upper bound does not reach the requested upper
1459 176 storres
        #  upper bound: compute the next upper bound.
1460 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
1461 176 storres
        #  enlarge the interval
1462 218 storres
        currentErrorRatio = approxAccurSa / errorSa
1463 176 storres
        ## --|--------------------------------------------------------------|--
1464 176 storres
        #  --|--------------------|--------------------------------------------
1465 176 storres
        #  --|----------------------------|------------------------------------
1466 176 storres
        ## Starting point for the next upper bound.
1467 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
1468 101 storres
        # Compute the increment.
1469 176 storres
        newBoundsWidthSa = \
1470 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
1471 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
1472 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
1473 176 storres
        # Take into account the original interval upper bound.
1474 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
1475 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
1476 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
1477 85 storres
            print "Can't shrink the interval anymore!"
1478 85 storres
            print "You should consider increasing the Sollya internal precision"
1479 85 storres
            print "or the polynomial degree."
1480 85 storres
            print "Giving up!"
1481 176 storres
            if precChangedSa:
1482 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
1483 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
1484 85 storres
            sollya_lib_clear_obj(functionSo)
1485 85 storres
            sollya_lib_clear_obj(degreeSo)
1486 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1487 85 storres
            return None
1488 176 storres
        # Compute the other expansions.
1489 176 storres
        # Test for insufficient precision.
1490 81 storres
# End slz_get_intervals_and_polynomials
1491 60 storres
1492 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
1493 61 storres
    """
1494 151 storres
    Compute the scaling expression to map an interval that spans at most
1495 166 storres
    a single binade into [1, 2) and the inverse expression as well.
1496 165 storres
    If the interval spans more than one binade, result is wrong since
1497 165 storres
    scaling is only based on the lower bound.
1498 62 storres
    Not very sure that the transformation makes sense for negative numbers.
1499 61 storres
    """
1500 165 storres
    # The "one of the bounds is 0" special case. Here we consider
1501 165 storres
    # the interval as the subnormals binade.
1502 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
1503 165 storres
        # The upper bound is (or should be) positive.
1504 165 storres
        if boundsInterval.endpoints()[0] == 0:
1505 165 storres
            if boundsInterval.endpoints()[1] == 0:
1506 165 storres
                return None
1507 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
1508 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
1509 165 storres
            # The upper bound is a power of two
1510 165 storres
            if binade == l2:
1511 165 storres
                scalingCoeff    = 2^(-binade)
1512 165 storres
                invScalingCoeff = 2^(binade)
1513 165 storres
                scalingOffset   = 1
1514 179 storres
                return \
1515 179 storres
                  ((scalingCoeff * expVar + scalingOffset).function(expVar),
1516 179 storres
                  ((expVar - scalingOffset) * invScalingCoeff).function(expVar))
1517 165 storres
            else:
1518 165 storres
                scalingCoeff    = 2^(-binade-1)
1519 165 storres
                invScalingCoeff = 2^(binade+1)
1520 165 storres
                scalingOffset   = 1
1521 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1522 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1523 165 storres
        # The lower bound is (or should be) negative.
1524 165 storres
        if boundsInterval.endpoints()[1] == 0:
1525 165 storres
            if boundsInterval.endpoints()[0] == 0:
1526 165 storres
                return None
1527 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
1528 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
1529 165 storres
            # The upper bound is a power of two
1530 165 storres
            if binade == l2:
1531 165 storres
                scalingCoeff    = -2^(-binade)
1532 165 storres
                invScalingCoeff = -2^(binade)
1533 165 storres
                scalingOffset   = 1
1534 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1535 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1536 165 storres
            else:
1537 165 storres
                scalingCoeff    = -2^(-binade-1)
1538 165 storres
                invScalingCoeff = -2^(binade+1)
1539 165 storres
                scalingOffset   = 1
1540 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1541 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
1542 165 storres
    # General case
1543 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
1544 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
1545 165 storres
    # We allow for a single exception in binade spanning is when the
1546 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
1547 165 storres
    # "inner bound" + 1.
1548 165 storres
    if boundsInterval.endpoints()[0] > 0:
1549 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
1550 165 storres
        if lbBinade != ubBinade:
1551 165 storres
            print "Different binades."
1552 165 storres
            if ubL2 != ubBinade:
1553 165 storres
                print "Not a power of 2."
1554 165 storres
                return None
1555 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1556 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1557 165 storres
                return None
1558 165 storres
    else:
1559 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
1560 165 storres
        if lbBinade != ubBinade:
1561 165 storres
            print "Different binades."
1562 165 storres
            if lbL2 != lbBinade:
1563 165 storres
                print "Not a power of 2."
1564 165 storres
                return None
1565 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1566 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1567 165 storres
                return None
1568 165 storres
    #print "Lower bound binade:", binade
1569 165 storres
    if boundsInterval.endpoints()[0] > 0:
1570 179 storres
        return \
1571 179 storres
            ((2^(-lbBinade) * expVar).function(expVar),
1572 179 storres
             (2^(lbBinade) * expVar).function(expVar))
1573 165 storres
    else:
1574 179 storres
        return \
1575 179 storres
            ((-(2^(-ubBinade)) * expVar).function(expVar),
1576 179 storres
             (-(2^(ubBinade)) * expVar).function(expVar))
1577 165 storres
"""
1578 165 storres
    # Code sent to attic. Should be the base for a
1579 165 storres
    # "slz_interval_translate_expression" rather than scale.
1580 165 storres
    # Extra control and special cases code  added in
1581 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
1582 165 storres
    # this new function.
1583 62 storres
    # The scaling offset is only used for negative numbers.
1584 151 storres
    # When the absolute value of the lower bound is < 0.
1585 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
1586 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1587 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1588 62 storres
            invScalingCoeff = 1/scalingCoeff
1589 80 storres
            return((scalingCoeff * expVar,
1590 80 storres
                    invScalingCoeff * expVar))
1591 60 storres
        else:
1592 62 storres
            scalingCoeff = \
1593 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
1594 62 storres
            scalingOffset = -3 * scalingCoeff
1595 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1596 80 storres
                    1/scalingCoeff * expVar + 3))
1597 61 storres
    else:
1598 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1599 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1600 61 storres
            scalingOffset = 0
1601 80 storres
            return((scalingCoeff * expVar,
1602 80 storres
                    1/scalingCoeff * expVar))
1603 61 storres
        else:
1604 62 storres
            scalingCoeff = \
1605 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1606 62 storres
            scalingOffset =  -3 * scalingCoeff
1607 62 storres
            #scalingOffset = 0
1608 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1609 80 storres
                    1/scalingCoeff * expVar + 3))
1610 165 storres
"""
1611 151 storres
# End slz_interval_scaling_expression
1612 61 storres
1613 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1614 72 storres
    """
1615 72 storres
    Compute the Sage version of the Taylor polynomial and it's
1616 72 storres
    companion data (interval, center...)
1617 72 storres
    The input parameter is a five elements tuple:
1618 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1619 79 storres
           real ring;
1620 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1621 79 storres
           over a real ring;
1622 72 storres
    - [2]: the interval (as Sollya range);
1623 72 storres
    - [3]: the interval center;
1624 72 storres
    - [4]: the approximation error.
1625 72 storres
1626 218 storres
    The function returns a 5 elements tuple: formed with all the
1627 72 storres
    input elements converted into their Sollya counterpart.
1628 72 storres
    """
1629 218 storres
    polynomialSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[0])
1630 218 storres
    #print "Polynomial after first conversion: ", pobyso_autoprint(polyRangeCenterErrorSo[1])
1631 218 storres
    polynomialChangedVarSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[1])
1632 60 storres
    intervalSa = \
1633 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1634 60 storres
    centerSa = \
1635 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1636 60 storres
    errorSa = \
1637 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1638 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1639 83 storres
    # End slz_interval_and_polynomial_to_sage
1640 62 storres
1641 172 storres
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None,
1642 172 storres
            targetPlusOnePrecRF = None, quasiExactRF = None):
1643 172 storres
    """
1644 172 storres
      Check if an element (argument) of the domain of function (function)
1645 172 storres
      yields a HTRN case (rounding to next) for the target precision
1646 183 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuracy).
1647 205 storres
1648 205 storres
      The strategy is:
1649 205 storres
      - compute the image at high (quasi-exact) precision;
1650 205 storres
      - round it to nearest to precision;
1651 205 storres
      - round it to exactly to (precision+1), the computed number has two
1652 205 storres
        midpoint neighbors;
1653 205 storres
      - check the distance between these neighbors and the quasi-exact value;
1654 205 storres
        - if none of them is closer than the targetAccuracy, return False,
1655 205 storres
        - else return true.
1656 205 storres
      - Powers of two are a special case when comparing the midpoint in
1657 205 storres
        the 0 direction..
1658 172 storres
    """
1659 183 storres
    ## Arguments filtering.
1660 183 storres
    ## TODO: filter the first argument for consistence.
1661 172 storres
    if targetRF is None:
1662 172 storres
        targetRF = argument.parent()
1663 172 storres
    ## Ditto for the real field holding the midpoints.
1664 172 storres
    if targetPlusOnePrecRF is None:
1665 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1666 183 storres
    ## If no quasiExactField is provided, create a high accuracy RealField.
1667 172 storres
    if quasiExactRF is None:
1668 172 storres
        quasiExactRF = RealField(1536)
1669 195 storres
    function                      = function.function(function.variables()[0])
1670 172 storres
    exactArgument                 = quasiExactRF(argument)
1671 172 storres
    quasiExactValue               = function(exactArgument)
1672 172 storres
    roundedValue                  = targetRF(quasiExactValue)
1673 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1674 172 storres
    # Upper midpoint.
1675 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1676 172 storres
    # Lower midpoint.
1677 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1678 172 storres
    binade                        = slz_compute_binade(roundedValue)
1679 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1680 172 storres
    #print "Argument:", argument
1681 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1682 174 storres
    #print "Binade:", binade
1683 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1684 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
1685 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1686 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1687 172 storres
    #print "Upper midpoint:", \
1688 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1689 172 storres
    #print "Rounded value :", \
1690 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1691 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1692 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1693 172 storres
    #print "Lower midpoint:", \
1694 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1695 205 storres
    ## Make quasiExactValue = 0 a special case to move it out of the way.
1696 205 storres
    if quasiExactValue == 0:
1697 205 storres
        return False
1698 205 storres
    ## Begining of the general case : check with the midpoint of
1699 172 storres
    #  greatest absolute value.
1700 172 storres
    if quasiExactValue > 0:
1701 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1702 172 storres
           binadeCorrectedTargetAccuracy:
1703 183 storres
            #print "Too close to the upper midpoint: ", \
1704 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1705 172 storres
            #print argument.n().str(base=16, \
1706 172 storres
            #  no_sci=False)
1707 172 storres
            #print "Lower midpoint:", \
1708 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1709 172 storres
            #print "Value         :", \
1710 183 storres
            # quasiExactValue.n(prec=200).str(base=2)
1711 172 storres
            #print "Upper midpoint:", \
1712 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1713 172 storres
            return True
1714 205 storres
    else: # quasiExactValue < 0, the 0 case has been previously filtered out.
1715 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1716 172 storres
           binadeCorrectedTargetAccuracy:
1717 172 storres
            #print "Too close to the upper midpoint: ", \
1718 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1719 172 storres
            #print argument.n().str(base=16, \
1720 172 storres
            #  no_sci=False)
1721 172 storres
            #print "Lower midpoint:", \
1722 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1723 172 storres
            #print "Value         :", \
1724 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1725 172 storres
            #print "Upper midpoint:", \
1726 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1727 172 storres
            #print
1728 172 storres
            return True
1729 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1730 172 storres
    ## For the midpoint of smaller absolute value,
1731 172 storres
    #  split cases with the powers of 2.
1732 172 storres
    if sno_abs_is_power_of_two(roundedValue):
1733 172 storres
        if quasiExactValue > 0:
1734 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1735 172 storres
               binadeCorrectedTargetAccuracy / 2:
1736 172 storres
                #print "Lower midpoint:", \
1737 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1738 172 storres
                #print "Value         :", \
1739 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1740 172 storres
                #print "Upper midpoint:", \
1741 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1742 172 storres
                #print
1743 172 storres
                return True
1744 172 storres
        else:
1745 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1746 172 storres
              binadeCorrectedTargetAccuracy / 2:
1747 172 storres
                #print "Lower midpoint:", \
1748 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1749 172 storres
                #print "Value         :",
1750 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1751 172 storres
                #print "Upper midpoint:",
1752 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1753 172 storres
                #print
1754 172 storres
                return True
1755 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1756 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
1757 172 storres
          #  smaller absolute value.
1758 172 storres
        if quasiExactValue > 0:
1759 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1760 172 storres
              binadeCorrectedTargetAccuracy:
1761 172 storres
                #print "Lower midpoint:", \
1762 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1763 172 storres
                #print "Value         :", \
1764 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1765 172 storres
                #print "Upper midpoint:", \
1766 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1767 172 storres
                #print
1768 172 storres
                return True
1769 172 storres
        else: # quasiExactValue <= 0
1770 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1771 172 storres
              binadeCorrectedTargetAccuracy:
1772 172 storres
                #print "Lower midpoint:", \
1773 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1774 172 storres
                #print "Value         :", \
1775 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1776 172 storres
                #print "Upper midpoint:", \
1777 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1778 172 storres
                #print
1779 172 storres
                return True
1780 172 storres
    #print "distance to the upper midpoint:", \
1781 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1782 172 storres
    #print "distance to the lower midpoint:", \
1783 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1784 172 storres
    return False
1785 172 storres
# End slz_is_htrn
1786 172 storres
1787 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
1788 80 storres
                                                precision,
1789 80 storres
                                                targetHardnessToRound,
1790 80 storres
                                                variable1,
1791 80 storres
                                                variable2):
1792 80 storres
    """
1793 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
1794 90 storres
     with the Coppersmith method.
1795 80 storres
    A the same time it computes :
1796 80 storres
    - 2^K (N);
1797 90 storres
    - 2^k (bound on the second variable)
1798 80 storres
    - lcm
1799 90 storres
1800 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1801 90 storres
                         variables.
1802 90 storres
    :param precision: the precision of the floating-point coefficients.
1803 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
1804 90 storres
    :param variable1: the first variable of the polynomial (an expression).
1805 90 storres
    :param variable2: the second variable of the polynomial (an expression).
1806 90 storres
1807 90 storres
    :returns: a 4 elements tuple:
1808 90 storres
                - the polynomial;
1809 91 storres
                - the modulus (N);
1810 91 storres
                - the t bound;
1811 90 storres
                - the lcm used to compute the integral coefficients and the
1812 90 storres
                  module.
1813 80 storres
    """
1814 80 storres
    # Create a new integer polynomial ring.
1815 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1816 80 storres
    # Coefficients are issued in the increasing power order.
1817 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1818 91 storres
    # Print the reversed list for debugging.
1819 179 storres
    #print
1820 179 storres
    #print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1821 94 storres
    # Build the list of number we compute the lcm of.
1822 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1823 179 storres
    #print "Coefficient denominators:", coefficientDenominators
1824 80 storres
    coefficientDenominators.append(2^precision)
1825 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
1826 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
1827 80 storres
    # Compute the expression corresponding to the new polynomial
1828 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1829 91 storres
    #print coefficientNumerators
1830 80 storres
    polynomialExpression = 0
1831 80 storres
    power = 0
1832 170 storres
    # Iterate over two lists at the same time, stop when the shorter
1833 170 storres
    # (is this case coefficientsNumerators) is
1834 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
1835 170 storres
    # of variable1.
1836 80 storres
    for numerator, denominator in \
1837 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
1838 80 storres
        multiplicator = leastCommonMultiple / denominator
1839 80 storres
        newCoefficient = numerator * multiplicator
1840 80 storres
        polynomialExpression += newCoefficient * variable1^power
1841 80 storres
        power +=1
1842 80 storres
    polynomialExpression += - variable2
1843 80 storres
    return (IP(polynomialExpression),
1844 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
1845 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1846 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1847 91 storres
            leastCommonMultiple) # If we want to make test computations.
1848 80 storres
1849 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1850 79 storres
1851 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
1852 79 storres
                                          precision):
1853 79 storres
    """
1854 79 storres
    Makes a variable substitution into the input polynomial so that the output
1855 79 storres
    polynomial can take integer arguments.
1856 79 storres
    All variables of the input polynomial "have precision p". That is to say
1857 103 storres
    that they are rationals with denominator == 2^(precision - 1):
1858 103 storres
    x = y/2^(precision - 1).
1859 79 storres
    We "incorporate" these denominators into the coefficients with,
1860 79 storres
    respectively, the "right" power.
1861 79 storres
    """
1862 79 storres
    polynomialField = ratPolyOfRat.parent()
1863 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
1864 91 storres
    #print "The polynomial field is:", polynomialField
1865 79 storres
    return \
1866 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1867 79 storres
                                   polynomialVariable/2^(precision-1)}))
1868 79 storres
1869 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1870 79 storres
1871 177 storres
def slz_reduce_and_test_base(matrixToReduce,
1872 177 storres
                             nAtAlpha,
1873 177 storres
                             monomialsCountSqrt):
1874 177 storres
    """
1875 177 storres
    Reduces the basis, tests the Coppersmith condition and returns
1876 177 storres
    a list of rows that comply with the condition.
1877 177 storres
    """
1878 177 storres
    ccComplientRowsList = []
1879 177 storres
    reducedMatrix = matrixToReduce.LLL(None)
1880 177 storres
    if not reducedMatrix.is_LLL_reduced():
1881 177 storres
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
1882 177 storres
    else:
1883 177 storres
        print "reducedMatrix is actually reduced."
1884 177 storres
    print "N^alpha:", nAtAlpha.n()
1885 177 storres
    rowIndex = 0
1886 177 storres
    for row in reducedMatrix.rows():
1887 177 storres
        l2Norm = row.norm(2)
1888 177 storres
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
1889 177 storres
                monomialsCountSqrt.n(), ". Is vector OK?",
1890 177 storres
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
1891 177 storres
            ccComplientRowsList.append(row)
1892 177 storres
            print "True"
1893 177 storres
        else:
1894 177 storres
            print "False"
1895 177 storres
    # End for
1896 177 storres
    return ccComplientRowsList
1897 177 storres
# End slz_reduce_and_test_base
1898 115 storres
1899 205 storres
def slz_resultant(poly1, poly2, elimVar):
1900 205 storres
    """
1901 205 storres
    Compute the resultant for two polynomials for a given variable
1902 205 storres
    and return the (poly1, poly2, resultant) if the resultant
1903 205 storres
    is not 0.
1904 205 storres
    Return () otherwise.
1905 205 storres
    """
1906 205 storres
    polynomialRing0    = poly1.parent()
1907 205 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1908 213 storres
    if resultantInElimVar is None:
1909 213 storres
        return None
1910 205 storres
    if resultantInElimVar.is_zero():
1911 205 storres
        return None
1912 205 storres
    else:
1913 205 storres
        return resultantInElimVar
1914 205 storres
# End slz_resultant.
1915 205 storres
#
1916 177 storres
def slz_resultant_tuple(poly1, poly2, elimVar):
1917 179 storres
    """
1918 179 storres
    Compute the resultant for two polynomials for a given variable
1919 179 storres
    and return the (poly1, poly2, resultant) if the resultant
1920 180 storres
    is not 0.
1921 179 storres
    Return () otherwise.
1922 179 storres
    """
1923 181 storres
    polynomialRing0    = poly1.parent()
1924 177 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1925 180 storres
    if resultantInElimVar.is_zero():
1926 177 storres
        return ()
1927 177 storres
    else:
1928 177 storres
        return (poly1, poly2, resultantInElimVar)
1929 177 storres
# End slz_resultant_tuple.
1930 177 storres
#
1931 87 storres
print "\t...sageSLZ loaded"