Statistiques
| Révision :

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

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