Statistiques
| Révision :

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

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

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