Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (86,44 ko)

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