Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (105,76 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 272 storres
                                        precSa=None, debug=False):
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 272 storres
    Argument debug is not used.
877 156 storres
    OUTPUT:
878 124 storres
    A tuple made of 4 Sollya objects:
879 124 storres
    - a polynomial;
880 124 storres
    - an range (an interval, not in the sense of number given as an interval);
881 124 storres
    - the center of the interval;
882 124 storres
    - the maximum error in the approximation of the input functionSo by the
883 218 storres
      output polynomial ; this error <= approxAccurSaS.
884 124 storres
885 61 storres
    """
886 218 storres
    #print"In slz_compute_polynomial_and_interval..."
887 166 storres
    ## Superficial argument check.
888 166 storres
    if lowerBoundSa > upperBoundSa:
889 166 storres
        return None
890 218 storres
    ## Change Sollya precision, if requested.
891 218 storres
    if precSa is None:
892 218 storres
        precSa = ceil((RR('1.5') * abs(RR(approxAccurSa).log2())) / 64) * 64
893 218 storres
        #print "Computed internal precision:", precSa
894 218 storres
        if precSa < 192:
895 218 storres
            precSa = 192
896 226 storres
    sollyaPrecChanged = False
897 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
898 226 storres
    if precSa > initialSollyaPrecSa:
899 226 storres
        if precSa <= 2:
900 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
901 226 storres
        pobyso_set_prec_sa_so(precSa)
902 218 storres
        sollyaPrecChanged = True
903 61 storres
    RRR = lowerBoundSa.parent()
904 176 storres
    intervalShrinkConstFactorSa = RRR('0.9')
905 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
906 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
907 61 storres
    currentUpperBoundSa = upperBoundSa
908 61 storres
    currentLowerBoundSa = lowerBoundSa
909 61 storres
    # What we want here is the polynomial without the variable change,
910 61 storres
    # since our actual variable will be x-intervalCenter defined over the
911 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
912 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
913 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
914 61 storres
                                                    currentRangeSo,
915 61 storres
                                                    absoluteErrorTypeSo)
916 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
917 218 storres
    while maxErrorSa > approxAccurSa:
918 181 storres
        print "++Approximation error:", maxErrorSa.n()
919 81 storres
        sollya_lib_clear_obj(polySo)
920 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
921 120 storres
        sollya_lib_clear_obj(maxErrorSo)
922 181 storres
        # Very empirical shrinking factor.
923 218 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
924 181 storres
        print "Shrink factor:", \
925 181 storres
              shrinkFactorSa.n(), \
926 181 storres
              intervalShrinkConstFactorSa
927 182 storres
        print
928 218 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
929 61 storres
        #print "Error ratio: ", errorRatioSa
930 181 storres
        # Make sure interval shrinks.
931 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
932 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
933 81 storres
            #print "Fixed"
934 61 storres
        else:
935 81 storres
            actualShrinkFactorSa = shrinkFactorSa
936 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
937 81 storres
            #print shrinkFactorSa, maxErrorSa
938 101 storres
        #print "Shrink factor", actualShrinkFactorSa
939 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
940 181 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
941 181 storres
                                actualShrinkFactorSa
942 71 storres
        #print "Current upper bound:", currentUpperBoundSa
943 61 storres
        sollya_lib_clear_obj(currentRangeSo)
944 181 storres
        # Check what is left with the bounds.
945 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
946 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
947 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
948 86 storres
            print "Can't find an interval."
949 86 storres
            print "Use either or both a higher polynomial degree or a higher",
950 86 storres
            print "internal precision."
951 86 storres
            print "Aborting!"
952 218 storres
            if sollyaPrecChanged:
953 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
954 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
955 218 storres
            return None
956 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
957 61 storres
                                                      currentUpperBoundSa)
958 86 storres
        # print "New interval:",
959 86 storres
        # pobyso_autoprint(currentRangeSo)
960 120 storres
        #print "Second Taylor expansion call."
961 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
962 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
963 61 storres
                                                        currentRangeSo,
964 61 storres
                                                        absoluteErrorTypeSo)
965 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
966 85 storres
        #print "Max errorSo:",
967 85 storres
        #pobyso_autoprint(maxErrorSo)
968 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
969 85 storres
        #print "Max errorSa:", maxErrorSa
970 85 storres
        #print "Sollya prec:",
971 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
972 218 storres
    # End while
973 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
974 218 storres
    if sollyaPrecChanged:
975 226 storres
        pobyso_set_prec_so_so(initialSollyaPrecSo)
976 226 storres
    sollya_lib_clear_obj(initialSollyaPrecSo)
977 176 storres
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
978 81 storres
# End slz_compute_polynomial_and_interval
979 218 storres
980 218 storres
def slz_compute_polynomial_and_interval_01(functionSo, degreeSo, lowerBoundSa,
981 218 storres
                                        upperBoundSa, approxAccurSa,
982 219 storres
                                        sollyaPrecSa=None, debug=False):
983 219 storres
    """
984 219 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
985 219 storres
    a polynomial that approximates the function on a an interval starting
986 219 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
987 219 storres
    approximates with the expected precision.
988 219 storres
    The interval upper bound is lowered until the expected approximation
989 219 storres
    precision is reached.
990 219 storres
    The polynomial, the bounds, the center of the interval and the error
991 219 storres
    are returned.
992 219 storres
    OUTPUT:
993 219 storres
    A tuple made of 4 Sollya objects:
994 219 storres
    - a polynomial;
995 219 storres
    - an range (an interval, not in the sense of number given as an interval);
996 219 storres
    - the center of the interval;
997 219 storres
    - the maximum error in the approximation of the input functionSo by the
998 219 storres
      output polynomial ; this error <= approxAccurSaS.
999 272 storres
1000 272 storres
    Changes from version 0 (no number):
1001 272 storres
    - make use of debug argument;
1002 272 storres
    - polynomial coefficients are "shaved".
1003 219 storres
1004 219 storres
    """
1005 219 storres
    #print"In slz_compute_polynomial_and_interval..."
1006 219 storres
    ## Superficial argument check.
1007 219 storres
    if lowerBoundSa > upperBoundSa:
1008 225 storres
        print inspect.stack()[0][3], ": lower bound is larger than upper bound. "
1009 219 storres
        return None
1010 219 storres
    ## Change Sollya precision, if requested.
1011 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
1012 225 storres
    sollyaPrecChangedSa = False
1013 225 storres
    if sollyaPrecSa is None:
1014 226 storres
        sollyaPrecSa = initialSollyaPrecSa
1015 219 storres
    else:
1016 226 storres
        if sollyaPrecSa > initialSollyaPrecSa:
1017 226 storres
            if sollyaPrecSa <= 2:
1018 226 storres
                print inspect.stack()[0][3], ": precision change <= 2 requested."
1019 225 storres
            pobyso_set_prec_sa_so(sollyaPrecSa)
1020 225 storres
            sollyaPrecChangedSa = True
1021 225 storres
    ## Other initializations and data recovery.
1022 219 storres
    RRR = lowerBoundSa.parent()
1023 219 storres
    intervalShrinkConstFactorSa = RRR('0.9')
1024 219 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
1025 219 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
1026 219 storres
    currentUpperBoundSa = upperBoundSa
1027 219 storres
    currentLowerBoundSa = lowerBoundSa
1028 219 storres
    # What we want here is the polynomial without the variable change,
1029 219 storres
    # since our actual variable will be x-intervalCenter defined over the
1030 219 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
1031 219 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
1032 219 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
1033 219 storres
                                                    currentRangeSo,
1034 219 storres
                                                    absoluteErrorTypeSo)
1035 219 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1036 219 storres
    while maxErrorSa > approxAccurSa:
1037 219 storres
        print "++Approximation error:", maxErrorSa.n()
1038 219 storres
        sollya_lib_clear_obj(polySo)
1039 219 storres
        sollya_lib_clear_obj(intervalCenterSo)
1040 219 storres
        sollya_lib_clear_obj(maxErrorSo)
1041 219 storres
        # Very empirical shrinking factor.
1042 219 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
1043 219 storres
        print "Shrink factor:", \
1044 219 storres
              shrinkFactorSa.n(), \
1045 219 storres
              intervalShrinkConstFactorSa
1046 219 storres
        print
1047 219 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
1048 219 storres
        #print "Error ratio: ", errorRatioSa
1049 219 storres
        # Make sure interval shrinks.
1050 219 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
1051 219 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
1052 219 storres
            #print "Fixed"
1053 219 storres
        else:
1054 219 storres
            actualShrinkFactorSa = shrinkFactorSa
1055 219 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
1056 219 storres
            #print shrinkFactorSa, maxErrorSa
1057 219 storres
        #print "Shrink factor", actualShrinkFactorSa
1058 219 storres
        currentUpperBoundSa = currentLowerBoundSa + \
1059 219 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
1060 219 storres
                                actualShrinkFactorSa
1061 219 storres
        #print "Current upper bound:", currentUpperBoundSa
1062 219 storres
        sollya_lib_clear_obj(currentRangeSo)
1063 219 storres
        # Check what is left with the bounds.
1064 219 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
1065 219 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
1066 219 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
1067 219 storres
            print "Can't find an interval."
1068 219 storres
            print "Use either or both a higher polynomial degree or a higher",
1069 219 storres
            print "internal precision."
1070 219 storres
            print "Aborting!"
1071 225 storres
            if sollyaPrecChangedSa:
1072 225 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1073 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1074 219 storres
            return None
1075 219 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
1076 219 storres
                                                      currentUpperBoundSa)
1077 219 storres
        # print "New interval:",
1078 219 storres
        # pobyso_autoprint(currentRangeSo)
1079 219 storres
        #print "Second Taylor expansion call."
1080 219 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
1081 219 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
1082 219 storres
                                                        currentRangeSo,
1083 219 storres
                                                        absoluteErrorTypeSo)
1084 219 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
1085 219 storres
        #print "Max errorSo:",
1086 219 storres
        #pobyso_autoprint(maxErrorSo)
1087 219 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1088 219 storres
        #print "Max errorSa:", maxErrorSa
1089 219 storres
        #print "Sollya prec:",
1090 219 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
1091 219 storres
    # End while
1092 219 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
1093 219 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
1094 219 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
1095 219 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
1096 219 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
1097 219 storres
    if debug:
1098 229 storres
        print inspect.stack()[0][3], "SollyaPrecSa:", sollyaPrecSa
1099 219 storres
        print "About to call polynomial rounding with:"
1100 219 storres
        print "polySo: ",           ; pobyso_autoprint(polySo)
1101 219 storres
        print "functionSo: ",       ; pobyso_autoprint(functionSo)
1102 219 storres
        print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
1103 219 storres
        print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
1104 219 storres
        print "itpSo: ",            ; pobyso_autoprint(itpSo)
1105 219 storres
        print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
1106 219 storres
        print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
1107 219 storres
        print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
1108 224 storres
    """
1109 224 storres
    # Naive rounding.
1110 219 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
1111 219 storres
    pobyso_polynomial_coefficients_progressive_round_so_so(polySo,
1112 219 storres
                                                           functionSo,
1113 219 storres
                                                           intervalCenterSo,
1114 219 storres
                                                           currentRangeSo,
1115 219 storres
                                                           itpSo,
1116 219 storres
                                                           ftpSo,
1117 219 storres
                                                           maxPrecSo,
1118 219 storres
                                                           approxAccurSo)
1119 224 storres
    """
1120 224 storres
    # Proved rounding.
1121 224 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
1122 224 storres
        pobyso_round_coefficients_progressive_so_so(polySo,
1123 224 storres
                                                    functionSo,
1124 224 storres
                                                    maxPrecSo,
1125 224 storres
                                                    currentRangeSo,
1126 224 storres
                                                    intervalCenterSo,
1127 224 storres
                                                    maxErrorSo,
1128 224 storres
                                                    approxAccurSo,
1129 224 storres
                                                    debug=False)
1130 224 storres
    #### Comment out the two next lines when polynomial rounding is activated.
1131 224 storres
    #roundedPolySo = sollya_lib_copy_obj(polySo)
1132 224 storres
    #roundedPolyMaxErrSo =  sollya_lib_copy_obj(maxErrorSo)
1133 219 storres
    sollya_lib_clear_obj(polySo)
1134 219 storres
    sollya_lib_clear_obj(maxErrorSo)
1135 219 storres
    sollya_lib_clear_obj(itpSo)
1136 219 storres
    sollya_lib_clear_obj(ftpSo)
1137 219 storres
    sollya_lib_clear_obj(approxAccurSo)
1138 225 storres
    if sollyaPrecChangedSa:
1139 230 storres
        pobyso_set_prec_so_so(initialSollyaPrecSo)
1140 230 storres
    sollya_lib_clear_obj(initialSollyaPrecSo)
1141 219 storres
    if debug:
1142 219 storres
        print "1: ", ; pobyso_autoprint(roundedPolySo)
1143 219 storres
        print "2: ", ; pobyso_autoprint(currentRangeSo)
1144 219 storres
        print "3: ", ; pobyso_autoprint(intervalCenterSo)
1145 219 storres
        print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
1146 219 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
1147 219 storres
# End slz_compute_polynomial_and_interval_01
1148 219 storres
1149 219 storres
def slz_compute_polynomial_and_interval_02(functionSo, degreeSo, lowerBoundSa,
1150 219 storres
                                        upperBoundSa, approxAccurSa,
1151 227 storres
                                        sollyaPrecSa=None, debug=True ):
1152 218 storres
    """
1153 218 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
1154 218 storres
    a polynomial that approximates the function on a an interval starting
1155 218 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
1156 218 storres
    approximates with the expected precision.
1157 218 storres
    The interval upper bound is lowered until the expected approximation
1158 218 storres
    precision is reached.
1159 218 storres
    The polynomial, the bounds, the center of the interval and the error
1160 218 storres
    are returned.
1161 218 storres
    OUTPUT:
1162 218 storres
    A tuple made of 4 Sollya objects:
1163 218 storres
    - a polynomial;
1164 218 storres
    - an range (an interval, not in the sense of number given as an interval);
1165 218 storres
    - the center of the interval;
1166 218 storres
    - the maximum error in the approximation of the input functionSo by the
1167 218 storres
      output polynomial ; this error <= approxAccurSaS.
1168 228 storres
    Changes fom v 01:
1169 227 storres
        extra verbose.
1170 218 storres
    """
1171 218 storres
    print"In slz_compute_polynomial_and_interval..."
1172 218 storres
    ## Superficial argument check.
1173 218 storres
    if lowerBoundSa > upperBoundSa:
1174 218 storres
        return None
1175 218 storres
    ## Change Sollya precision, if requested.
1176 226 storres
    sollyaPrecChanged = False
1177 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
1178 227 storres
    #print "Initial Sollya prec:", initialSollyaPrecSa, type(initialSollyaPrecSa)
1179 227 storres
    if sollyaPrecSa is None:
1180 226 storres
        sollyaPrecSa = initialSollyaPrecSa
1181 226 storres
    else:
1182 226 storres
        if sollyaPrecSa <= 2:
1183 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
1184 218 storres
        pobyso_set_prec_sa_so(sollyaPrecSa)
1185 226 storres
        sollyaPrecChanged = True
1186 218 storres
    RRR = lowerBoundSa.parent()
1187 218 storres
    intervalShrinkConstFactorSa = RRR('0.9')
1188 218 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
1189 218 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
1190 218 storres
    currentUpperBoundSa = upperBoundSa
1191 218 storres
    currentLowerBoundSa = lowerBoundSa
1192 227 storres
    #pobyso_autoprint(functionSo)
1193 227 storres
    #pobyso_autoprint(degreeSo)
1194 227 storres
    #pobyso_autoprint(currentRangeSo)
1195 227 storres
    #pobyso_autoprint(absoluteErrorTypeSo)
1196 227 storres
    ## What we want here is the polynomial without the variable change,
1197 227 storres
    #  since our actual variable will be x-intervalCenter defined over the
1198 227 storres
    #  domain [lowerBound-intervalCenter , upperBound-intervalCenter].
1199 218 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
1200 218 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
1201 218 storres
                                                    currentRangeSo,
1202 218 storres
                                                    absoluteErrorTypeSo)
1203 218 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1204 227 storres
    print "...after Taylor expansion."
1205 218 storres
    while maxErrorSa > approxAccurSa:
1206 218 storres
        print "++Approximation error:", maxErrorSa.n()
1207 218 storres
        sollya_lib_clear_obj(polySo)
1208 218 storres
        sollya_lib_clear_obj(intervalCenterSo)
1209 218 storres
        sollya_lib_clear_obj(maxErrorSo)
1210 218 storres
        # Very empirical shrinking factor.
1211 218 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxAccurSa).log2().abs()
1212 218 storres
        print "Shrink factor:", \
1213 218 storres
              shrinkFactorSa.n(), \
1214 218 storres
              intervalShrinkConstFactorSa
1215 218 storres
        print
1216 218 storres
        #errorRatioSa = approxAccurSa/maxErrorSa
1217 218 storres
        #print "Error ratio: ", errorRatioSa
1218 218 storres
        # Make sure interval shrinks.
1219 218 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
1220 218 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
1221 218 storres
            #print "Fixed"
1222 218 storres
        else:
1223 218 storres
            actualShrinkFactorSa = shrinkFactorSa
1224 218 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
1225 218 storres
            #print shrinkFactorSa, maxErrorSa
1226 218 storres
        #print "Shrink factor", actualShrinkFactorSa
1227 218 storres
        currentUpperBoundSa = currentLowerBoundSa + \
1228 218 storres
                                (currentUpperBoundSa - currentLowerBoundSa) * \
1229 218 storres
                                actualShrinkFactorSa
1230 218 storres
        #print "Current upper bound:", currentUpperBoundSa
1231 218 storres
        sollya_lib_clear_obj(currentRangeSo)
1232 218 storres
        # Check what is left with the bounds.
1233 218 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
1234 218 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
1235 218 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
1236 218 storres
            print "Can't find an interval."
1237 218 storres
            print "Use either or both a higher polynomial degree or a higher",
1238 218 storres
            print "internal precision."
1239 218 storres
            print "Aborting!"
1240 226 storres
            if sollyaPrecChanged:
1241 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1242 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1243 218 storres
            return None
1244 218 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
1245 218 storres
                                                      currentUpperBoundSa)
1246 218 storres
        # print "New interval:",
1247 218 storres
        # pobyso_autoprint(currentRangeSo)
1248 218 storres
        #print "Second Taylor expansion call."
1249 218 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
1250 218 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
1251 218 storres
                                                        currentRangeSo,
1252 218 storres
                                                        absoluteErrorTypeSo)
1253 218 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
1254 218 storres
        #print "Max errorSo:",
1255 218 storres
        #pobyso_autoprint(maxErrorSo)
1256 218 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1257 218 storres
        #print "Max errorSa:", maxErrorSa
1258 218 storres
        #print "Sollya prec:",
1259 218 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
1260 218 storres
    # End while
1261 218 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
1262 218 storres
    itpSo           = pobyso_constant_from_int_sa_so(floor(sollyaPrecSa/3))
1263 218 storres
    ftpSo           = pobyso_constant_from_int_sa_so(floor(2*sollyaPrecSa/3))
1264 218 storres
    maxPrecSo       = pobyso_constant_from_int_sa_so(sollyaPrecSa)
1265 218 storres
    approxAccurSo   = pobyso_constant_sa_so(RR(approxAccurSa))
1266 218 storres
    print "About to call polynomial rounding with:"
1267 218 storres
    print "polySo: ",           ; pobyso_autoprint(polySo)
1268 218 storres
    print "functionSo: ",       ; pobyso_autoprint(functionSo)
1269 218 storres
    print "intervalCenterSo: ", ; pobyso_autoprint(intervalCenterSo)
1270 218 storres
    print "currentRangeSo: ",   ; pobyso_autoprint(currentRangeSo)
1271 218 storres
    print "itpSo: ",            ; pobyso_autoprint(itpSo)
1272 218 storres
    print "ftpSo: ",            ; pobyso_autoprint(ftpSo)
1273 218 storres
    print "maxPrecSo: ",        ; pobyso_autoprint(maxPrecSo)
1274 218 storres
    print "approxAccurSo: ",    ; pobyso_autoprint(approxAccurSo)
1275 218 storres
    (roundedPolySo, roundedPolyMaxErrSo) = \
1276 228 storres
    pobyso_round_coefficients_progressive_so_so(polySo,
1277 228 storres
                                                functionSo,
1278 228 storres
                                                maxPrecSo,
1279 228 storres
                                                currentRangeSo,
1280 228 storres
                                                intervalCenterSo,
1281 228 storres
                                                maxErrorSo,
1282 228 storres
                                                approxAccurSo,
1283 228 storres
                                                debug = True)
1284 218 storres
1285 218 storres
    sollya_lib_clear_obj(polySo)
1286 218 storres
    sollya_lib_clear_obj(maxErrorSo)
1287 218 storres
    sollya_lib_clear_obj(itpSo)
1288 218 storres
    sollya_lib_clear_obj(ftpSo)
1289 218 storres
    sollya_lib_clear_obj(approxAccurSo)
1290 226 storres
    if sollyaPrecChanged:
1291 226 storres
        pobyso_set_prec_so_so(initialSollyaPrecSo)
1292 226 storres
    sollya_lib_clear_obj(initialSollyaPrecSo)
1293 218 storres
    print "1: ", ; pobyso_autoprint(roundedPolySo)
1294 218 storres
    print "2: ", ; pobyso_autoprint(currentRangeSo)
1295 218 storres
    print "3: ", ; pobyso_autoprint(intervalCenterSo)
1296 218 storres
    print "4: ", ; pobyso_autoprint(roundedPolyMaxErrSo)
1297 218 storres
    return (roundedPolySo, currentRangeSo, intervalCenterSo, roundedPolyMaxErrSo)
1298 219 storres
# End slz_compute_polynomial_and_interval_02
1299 218 storres
1300 122 storres
def slz_compute_reduced_polynomial(matrixRow,
1301 98 storres
                                    knownMonomials,
1302 106 storres
                                    var1,
1303 98 storres
                                    var1Bound,
1304 106 storres
                                    var2,
1305 99 storres
                                    var2Bound):
1306 98 storres
    """
1307 125 storres
    Compute a polynomial from a single reduced matrix row.
1308 122 storres
    This function was introduced in order to avoid the computation of the
1309 125 storres
    all the polynomials  from the full matrix (even those built from rows
1310 125 storres
    that do no verify the Coppersmith condition) as this may involves
1311 152 storres
    expensive operations over (large) integers.
1312 122 storres
    """
1313 122 storres
    ## Check arguments.
1314 122 storres
    if len(knownMonomials) == 0:
1315 122 storres
        return None
1316 122 storres
    # varNounds can be zero since 0^0 returns 1.
1317 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
1318 122 storres
        return None
1319 122 storres
    ## Initialisations.
1320 122 storres
    polynomialRing = knownMonomials[0].parent()
1321 122 storres
    currentPolynomial = polynomialRing(0)
1322 123 storres
    # TODO: use zip instead of indices.
1323 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
1324 122 storres
        currentCoefficient = matrixRow[colIndex]
1325 122 storres
        if currentCoefficient != 0:
1326 122 storres
            #print "Current coefficient:", currentCoefficient
1327 122 storres
            currentMonomial = knownMonomials[colIndex]
1328 122 storres
            #print "Monomial as multivariate polynomial:", \
1329 122 storres
            #currentMonomial, type(currentMonomial)
1330 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
1331 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
1332 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
1333 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
1334 122 storres
            if degreeInVar1 > 0:
1335 122 storres
                currentCoefficient = \
1336 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
1337 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
1338 122 storres
                #print "Current coefficient(1)", currentCoefficient
1339 122 storres
            if degreeInVar2 > 0:
1340 122 storres
                currentCoefficient = \
1341 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
1342 122 storres
                #print "Current coefficient(2)", currentCoefficient
1343 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
1344 122 storres
            #                                    currentMonomial)
1345 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
1346 122 storres
            #print "Current polynomial:", currentPolynomial
1347 122 storres
        # End if
1348 122 storres
    # End for colIndex.
1349 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
1350 122 storres
    return(currentPolynomial)
1351 122 storres
# End slz_compute_reduced_polynomial
1352 122 storres
#
1353 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
1354 122 storres
                                        knownMonomials,
1355 122 storres
                                        var1,
1356 122 storres
                                        var1Bound,
1357 122 storres
                                        var2,
1358 122 storres
                                        var2Bound):
1359 122 storres
    """
1360 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
1361 122 storres
    """
1362 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
1363 122 storres
                                                knownMonomials,
1364 122 storres
                                                var1,
1365 122 storres
                                                var1Bound,
1366 122 storres
                                                var2,
1367 122 storres
                                                var2Bound)
1368 122 storres
    )
1369 177 storres
#
1370 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
1371 152 storres
                                         knownMonomials,
1372 152 storres
                                         var1,
1373 152 storres
                                         var1Bound,
1374 152 storres
                                         var2,
1375 152 storres
                                         var2Bound):
1376 122 storres
    """
1377 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
1378 98 storres
    from the bounds of each variable, compute the corresponding polynomials
1379 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1380 99 storres
1381 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1382 172 storres
    They set the polynomial type of the output polynomials in list.
1383 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
1384 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1385 152 storres
                           build the polynomials;
1386 152 storres
    @param var1:           the first variable (of the "right" type);
1387 152 storres
    @param var1Bound:      the first variable bound;
1388 152 storres
    @param var2:           the second variable (of the "right" type);
1389 152 storres
    @param var2Bound:      the second variable bound.
1390 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
1391 152 storres
             and scaled down with the bounds
1392 98 storres
    """
1393 99 storres
1394 98 storres
    # TODO: check input arguments.
1395 98 storres
    reducedPolynomials = []
1396 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1397 98 storres
    for matrixRow in reducedMatrix.rows():
1398 102 storres
        currentPolynomial = 0
1399 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
1400 98 storres
            currentCoefficient = matrixRow[colIndex]
1401 106 storres
            if currentCoefficient != 0:
1402 106 storres
                #print "Current coefficient:", currentCoefficient
1403 106 storres
                currentMonomial = knownMonomials[colIndex]
1404 106 storres
                parentRing = currentMonomial.parent()
1405 106 storres
                #print "Monomial as multivariate polynomial:", \
1406 106 storres
                #currentMonomial, type(currentMonomial)
1407 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1408 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
1409 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1410 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
1411 106 storres
                if degreeInVar1 > 0:
1412 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1413 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1414 106 storres
                    #print "Current coefficient(1)", currentCoefficient
1415 106 storres
                if degreeInVar2 > 0:
1416 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1417 106 storres
                    #print "Current coefficient(2)", currentCoefficient
1418 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1419 106 storres
                #                                    currentMonomial)
1420 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1421 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1422 168 storres
                    #print "!!!! constant term !!!!"
1423 106 storres
                #print "Current polynomial:", currentPolynomial
1424 106 storres
            # End if
1425 106 storres
        # End for colIndex.
1426 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1427 99 storres
        reducedPolynomials.append(currentPolynomial)
1428 98 storres
    return reducedPolynomials
1429 177 storres
# End slz_compute_reduced_polynomials_list.
1430 98 storres
1431 177 storres
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
1432 177 storres
                                                   knownMonomials,
1433 177 storres
                                                   var1,
1434 177 storres
                                                   var1Bound,
1435 177 storres
                                                   var2,
1436 177 storres
                                                   var2Bound):
1437 177 storres
    """
1438 177 storres
    From a list of rows, holding the coefficients, from a monomials list,
1439 177 storres
    from the bounds of each variable, compute the corresponding polynomials
1440 177 storres
    scaled back by dividing by the "right" powers of the variables bounds.
1441 177 storres
1442 177 storres
    The elements in knownMonomials must be of the "right" polynomial type.
1443 177 storres
    They set the polynomial type of the output polynomials in list.
1444 177 storres
    @param rowsList:       the reduced matrix as output from LLL;
1445 177 storres
    @param kwnonMonomials: the ordered list of the monomials used to
1446 177 storres
                           build the polynomials;
1447 177 storres
    @param var1:           the first variable (of the "right" type);
1448 177 storres
    @param var1Bound:      the first variable bound;
1449 177 storres
    @param var2:           the second variable (of the "right" type);
1450 177 storres
    @param var2Bound:      the second variable bound.
1451 177 storres
    @return: a list of polynomials obtained with the reduced coefficients
1452 177 storres
             and scaled down with the bounds
1453 177 storres
    """
1454 177 storres
1455 177 storres
    # TODO: check input arguments.
1456 177 storres
    reducedPolynomials = []
1457 177 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
1458 177 storres
    for matrixRow in rowsList:
1459 177 storres
        currentPolynomial = 0
1460 177 storres
        for colIndex in xrange(0, len(knownMonomials)):
1461 177 storres
            currentCoefficient = matrixRow[colIndex]
1462 177 storres
            if currentCoefficient != 0:
1463 177 storres
                #print "Current coefficient:", currentCoefficient
1464 177 storres
                currentMonomial = knownMonomials[colIndex]
1465 177 storres
                parentRing = currentMonomial.parent()
1466 177 storres
                #print "Monomial as multivariate polynomial:", \
1467 177 storres
                #currentMonomial, type(currentMonomial)
1468 177 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
1469 177 storres
                #print "Degree in var", var1, ":", degreeInVar1
1470 177 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
1471 177 storres
                #print "Degree in var", var2, ":", degreeInVar2
1472 177 storres
                if degreeInVar1 > 0:
1473 177 storres
                    currentCoefficient /= var1Bound^degreeInVar1
1474 177 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
1475 177 storres
                    #print "Current coefficient(1)", currentCoefficient
1476 177 storres
                if degreeInVar2 > 0:
1477 177 storres
                    currentCoefficient /= var2Bound^degreeInVar2
1478 177 storres
                    #print "Current coefficient(2)", currentCoefficient
1479 177 storres
                #print "Current reduced monomial:", (currentCoefficient * \
1480 177 storres
                #                                    currentMonomial)
1481 177 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
1482 177 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
1483 177 storres
                    #print "!!!! constant term !!!!"
1484 177 storres
                #print "Current polynomial:", currentPolynomial
1485 177 storres
            # End if
1486 177 storres
        # End for colIndex.
1487 177 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
1488 177 storres
        reducedPolynomials.append(currentPolynomial)
1489 177 storres
    return reducedPolynomials
1490 177 storres
# End slz_compute_reduced_polynomials_list_from_rows.
1491 177 storres
#
1492 114 storres
def slz_compute_scaled_function(functionSa,
1493 114 storres
                                lowerBoundSa,
1494 114 storres
                                upperBoundSa,
1495 156 storres
                                floatingPointPrecSa,
1496 156 storres
                                debug=False):
1497 72 storres
    """
1498 72 storres
    From a function, compute the scaled function whose domain
1499 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
1500 72 storres
    Return a tuple:
1501 72 storres
    [0]: the scaled function
1502 72 storres
    [1]: the scaled domain lower bound
1503 72 storres
    [2]: the scaled domain upper bound
1504 72 storres
    [3]: the scaled image lower bound
1505 72 storres
    [4]: the scaled image upper bound
1506 72 storres
    """
1507 177 storres
    ## The variable can be called anything.
1508 80 storres
    x = functionSa.variables()[0]
1509 72 storres
    # Scalling the domain -> [1,2[.
1510 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
1511 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
1512 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
1513 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
1514 156 storres
    if debug:
1515 156 storres
        print "domainScalingExpression for argument :", \
1516 156 storres
        invDomainScalingExpressionSa
1517 190 storres
        print "function: ", functionSa
1518 190 storres
    ff = functionSa.subs({x : domainScalingExpressionSa})
1519 190 storres
    ## Bless expression as a function.
1520 190 storres
    ff = ff.function(x)
1521 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
1522 177 storres
    #domainScalingFunction(x) = invDomainScalingExpressionSa
1523 177 storres
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
1524 151 storres
    scaledLowerBoundSa = \
1525 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
1526 151 storres
    scaledUpperBoundSa = \
1527 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
1528 156 storres
    if debug:
1529 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
1530 156 storres
              scaledUpperBoundSa
1531 254 storres
    ## If both bounds are negative, swap them.
1532 254 storres
    if lowerBoundSa < 0 and upperBoundSa < 0:
1533 254 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
1534 254 storres
        scaledUpperBoundSa,scaledLowerBoundSa
1535 72 storres
    #
1536 72 storres
    # Scalling the image -> [1,2[.
1537 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
1538 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
1539 72 storres
    if flbSa <= fubSa: # Increasing
1540 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
1541 72 storres
    else: # Decreasing
1542 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
1543 156 storres
    if debug:
1544 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
1545 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
1546 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
1547 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
1548 156 storres
    if debug:
1549 156 storres
        print "imageScalingExpression for argument :", \
1550 156 storres
              invImageScalingExpressionSa
1551 72 storres
    iis = invImageScalingExpressionSa.function(x)
1552 72 storres
    fff = iis.subs({x:ff})
1553 156 storres
    if debug:
1554 156 storres
        print "fff:", fff,
1555 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
1556 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
1557 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
1558 151 storres
# End slz_compute_scaled_function
1559 72 storres
1560 179 storres
def slz_fix_bounds_for_binades(lowerBound,
1561 179 storres
                               upperBound,
1562 190 storres
                               func = None,
1563 179 storres
                               domainDirection = -1,
1564 179 storres
                               imageDirection  = -1):
1565 179 storres
    """
1566 179 storres
    Assuming the function is increasing or decreasing over the
1567 179 storres
    [lowerBound, upperBound] interval, return a lower bound lb and
1568 179 storres
    an upper bound ub such that:
1569 179 storres
    - lb and ub belong to the same binade;
1570 179 storres
    - func(lb) and func(ub) belong to the same binade.
1571 179 storres
    domainDirection indicate how bounds move to fit into the same binade:
1572 179 storres
    - a negative value move the upper bound down;
1573 179 storres
    - a positive value move the lower bound up.
1574 179 storres
    imageDirection indicate how bounds move in order to have their image
1575 179 storres
    fit into the same binade, variation of the function is also condidered.
1576 179 storres
    For an increasing function:
1577 179 storres
    - negative value moves the upper bound down (and its image value as well);
1578 179 storres
    - a positive values moves the lower bound up (and its image value as well);
1579 179 storres
    For a decreasing function it is the other way round.
1580 179 storres
    """
1581 179 storres
    ## Arguments check
1582 179 storres
    if lowerBound > upperBound:
1583 179 storres
        return None
1584 190 storres
    if lowerBound == upperBound:
1585 190 storres
        return (lowerBound, upperBound)
1586 179 storres
    if func is None:
1587 179 storres
        return None
1588 179 storres
    #
1589 179 storres
    #varFunc = func.variables()[0]
1590 179 storres
    lb = lowerBound
1591 179 storres
    ub = upperBound
1592 179 storres
    lbBinade = slz_compute_binade(lb)
1593 179 storres
    ubBinade = slz_compute_binade(ub)
1594 179 storres
    ## Domain binade.
1595 179 storres
    while lbBinade != ubBinade:
1596 179 storres
        newIntervalWidth = (ub - lb) / 2
1597 179 storres
        if domainDirection < 0:
1598 179 storres
            ub = lb + newIntervalWidth
1599 179 storres
            ubBinade = slz_compute_binade(ub)
1600 179 storres
        else:
1601 179 storres
            lb = lb + newIntervalWidth
1602 179 storres
            lbBinade = slz_compute_binade(lb)
1603 254 storres
    #print "sfbfb: lower bound:", lb.str(truncate=False)
1604 254 storres
    #print "sfbfb: upper bound:", ub.str(truncate=False)
1605 254 storres
    ## At this point, both bounds belond to the same binade.
1606 179 storres
    ## Image binade.
1607 179 storres
    if lb == ub:
1608 179 storres
        return (lb, ub)
1609 179 storres
    lbImg = func(lb)
1610 179 storres
    ubImg = func(ub)
1611 254 storres
    funcIsInc = ((ubImg - lbImg) >= 0)
1612 179 storres
    lbImgBinade = slz_compute_binade(lbImg)
1613 179 storres
    ubImgBinade = slz_compute_binade(ubImg)
1614 179 storres
    while lbImgBinade != ubImgBinade:
1615 179 storres
        newIntervalWidth = (ub - lb) / 2
1616 179 storres
        if imageDirection < 0:
1617 179 storres
            if funcIsInc:
1618 179 storres
                ub = lb + newIntervalWidth
1619 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1620 179 storres
                #print ubImgBinade
1621 179 storres
            else:
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
            if funcIsInc:
1627 179 storres
                lb = lb + newIntervalWidth
1628 179 storres
                lbImgBinade = slz_compute_binade(func(lb))
1629 179 storres
                #print lbImgBinade
1630 179 storres
            else:
1631 179 storres
                ub = lb + newIntervalWidth
1632 179 storres
                ubImgBinade = slz_compute_binade(func(ub))
1633 179 storres
                #print ubImgBinade
1634 179 storres
    # End while lbImgBinade != ubImgBinade:
1635 179 storres
    return (lb, ub)
1636 179 storres
# End slz_fix_bounds_for_binades.
1637 179 storres
1638 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
1639 79 storres
    # Create a polynomial over the rationals.
1640 179 storres
    ratPolynomialRing = QQ[str(polyOfFloat.variables()[0])]
1641 179 storres
    return(ratPolynomialRing(polyOfFloat))
1642 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1643 81 storres
1644 188 storres
def slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(polyOfFloat):
1645 188 storres
    """
1646 188 storres
     Create a polynomial over the rationals where all denominators are
1647 188 storres
     powers of two.
1648 188 storres
    """
1649 188 storres
    polyVariable = polyOfFloat.variables()[0]
1650 188 storres
    RPR = QQ[str(polyVariable)]
1651 188 storres
    polyCoeffs      = polyOfFloat.coefficients()
1652 188 storres
    #print polyCoeffs
1653 188 storres
    polyExponents   = polyOfFloat.exponents()
1654 188 storres
    #print polyExponents
1655 188 storres
    polyDenomPtwoCoeffs = []
1656 188 storres
    for coeff in polyCoeffs:
1657 188 storres
        polyDenomPtwoCoeffs.append(sno_float_to_rat_pow_of_two_denom(coeff))
1658 188 storres
        #print "Converted coefficient:", sno_float_to_rat_pow_of_two_denom(coeff),
1659 188 storres
        #print type(sno_float_to_rat_pow_of_two_denom(coeff))
1660 188 storres
    ratPoly = RPR(0)
1661 188 storres
    #print type(ratPoly)
1662 188 storres
    ## !!! CAUTION !!! Do not use the RPR(coeff * polyVariagle^exponent)
1663 188 storres
    #  The coefficient becomes plainly wrong when exponent == 0.
1664 188 storres
    #  No clue as to why.
1665 188 storres
    for coeff, exponent in zip(polyDenomPtwoCoeffs, polyExponents):
1666 188 storres
        ratPoly += coeff * RPR(polyVariable^exponent)
1667 188 storres
    return ratPoly
1668 188 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
1669 188 storres
1670 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
1671 63 storres
                                      lowerBoundSa,
1672 269 storres
                                      upperBoundSa,
1673 269 storres
                                      floatingPointPrecSa,
1674 269 storres
                                      internalSollyaPrecSa,
1675 269 storres
                                      approxAccurSa):
1676 60 storres
    """
1677 60 storres
    Under the assumption that:
1678 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
1679 60 storres
    - lowerBound and upperBound belong to the same binade.
1680 60 storres
    from a:
1681 60 storres
    - function;
1682 60 storres
    - a degree
1683 60 storres
    - a pair of bounds;
1684 60 storres
    - the floating-point precision we work on;
1685 60 storres
    - the internal Sollya precision;
1686 64 storres
    - the requested approximation error
1687 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
1688 61 storres
    It return a list of tuples, each made of:
1689 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
1690 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
1691 61 storres
    - the approximation interval;
1692 72 storres
    - the center, x0, of the interval;
1693 61 storres
    - the corresponding approximation error.
1694 100 storres
    TODO: fix endless looping for some parameters sets.
1695 60 storres
    """
1696 120 storres
    resultArray = []
1697 101 storres
    # Set Sollya to the necessary internal precision.
1698 226 storres
    sollyaPrecChangedSa = False
1699 226 storres
    (initialSollyaPrecSo, initialSollyaPrecSa) = pobyso_get_prec_so_so_sa()
1700 269 storres
    if internalSollyaPrecSa > initialSollyaPrecSa:
1701 226 storres
        if internalSollyaPrecSa <= 2:
1702 226 storres
            print inspect.stack()[0][3], ": precision change <=2 requested."
1703 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
1704 226 storres
        sollyaPrecChangedSa = True
1705 101 storres
    #
1706 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
1707 101 storres
    # Scaled function: [1=,2] -> [1,2].
1708 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
1709 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
1710 115 storres
                slz_compute_scaled_function(functionSa,                       \
1711 115 storres
                                            lowerBoundSa,                     \
1712 115 storres
                                            upperBoundSa,                     \
1713 80 storres
                                            floatingPointPrecSa)
1714 166 storres
    # In case bounds were in the negative real one may need to
1715 166 storres
    # switch scaled bounds.
1716 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
1717 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
1718 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
1719 166 storres
        #print "Switching!"
1720 218 storres
    print "Approximation accuracy: ", RR(approxAccurSa)
1721 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
1722 159 storres
    functionSo = \
1723 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
1724 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
1725 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
1726 61 storres
                                                  scaledUpperBoundSa)
1727 176 storres
1728 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
1729 60 storres
                                              upperBoundSa.parent().precision()))
1730 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
1731 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
1732 176 storres
    while True:
1733 176 storres
        ## Compute the first Taylor expansion.
1734 176 storres
        print "Computing a Taylor expansion..."
1735 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
1736 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
1737 176 storres
                                        currentScaledLowerBoundSa,
1738 176 storres
                                        currentScaledUpperBoundSa,
1739 218 storres
                                        approxAccurSa, internalSollyaPrecSa)
1740 176 storres
        print "...done."
1741 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
1742 176 storres
        #  This value goes to the first variable: polySo. Other variables are
1743 176 storres
        #  not assigned and should not be tested.
1744 176 storres
        if polySo is None:
1745 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
1746 176 storres
            if precChangedSa:
1747 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1748 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1749 176 storres
            sollya_lib_clear_obj(functionSo)
1750 176 storres
            sollya_lib_clear_obj(degreeSo)
1751 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1752 176 storres
            return None
1753 176 storres
        ## Add to the result array.
1754 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
1755 176 storres
        changeVarExpressionSo = \
1756 176 storres
            sollya_lib_build_function_sub( \
1757 176 storres
                              sollya_lib_build_function_free_variable(),
1758 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
1759 176 storres
        polyVarChangedSo = \
1760 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
1761 176 storres
        #### Get rid of the variable change Sollya stuff.
1762 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
1763 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
1764 101 storres
                            intervalCenterSo, maxErrorSo))
1765 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
1766 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
1767 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
1768 176 storres
        # If the error and interval are OK a the first try, just return.
1769 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
1770 218 storres
            (errorSa <= approxAccurSa):
1771 269 storres
            if sollyaPrecChangedSa:
1772 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1773 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1774 176 storres
            sollya_lib_clear_obj(functionSo)
1775 176 storres
            sollya_lib_clear_obj(degreeSo)
1776 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1777 101 storres
            #print "Approximation error:", errorSa
1778 176 storres
            return resultArray
1779 176 storres
        ## The returned interval upper bound does not reach the requested upper
1780 176 storres
        #  upper bound: compute the next upper bound.
1781 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
1782 176 storres
        #  enlarge the interval
1783 218 storres
        currentErrorRatio = approxAccurSa / errorSa
1784 176 storres
        ## --|--------------------------------------------------------------|--
1785 176 storres
        #  --|--------------------|--------------------------------------------
1786 176 storres
        #  --|----------------------------|------------------------------------
1787 176 storres
        ## Starting point for the next upper bound.
1788 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
1789 101 storres
        # Compute the increment.
1790 176 storres
        newBoundsWidthSa = \
1791 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
1792 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
1793 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
1794 176 storres
        # Take into account the original interval upper bound.
1795 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
1796 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
1797 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
1798 85 storres
            print "Can't shrink the interval anymore!"
1799 85 storres
            print "You should consider increasing the Sollya internal precision"
1800 85 storres
            print "or the polynomial degree."
1801 85 storres
            print "Giving up!"
1802 176 storres
            if precChangedSa:
1803 226 storres
                pobyso_set_prec_so_so(initialSollyaPrecSo)
1804 226 storres
            sollya_lib_clear_obj(initialSollyaPrecSo)
1805 85 storres
            sollya_lib_clear_obj(functionSo)
1806 85 storres
            sollya_lib_clear_obj(degreeSo)
1807 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
1808 85 storres
            return None
1809 176 storres
        # Compute the other expansions.
1810 176 storres
        # Test for insufficient precision.
1811 81 storres
# End slz_get_intervals_and_polynomials
1812 60 storres
1813 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
1814 61 storres
    """
1815 151 storres
    Compute the scaling expression to map an interval that spans at most
1816 166 storres
    a single binade into [1, 2) and the inverse expression as well.
1817 165 storres
    If the interval spans more than one binade, result is wrong since
1818 165 storres
    scaling is only based on the lower bound.
1819 62 storres
    Not very sure that the transformation makes sense for negative numbers.
1820 61 storres
    """
1821 165 storres
    # The "one of the bounds is 0" special case. Here we consider
1822 165 storres
    # the interval as the subnormals binade.
1823 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
1824 165 storres
        # The upper bound is (or should be) positive.
1825 165 storres
        if boundsInterval.endpoints()[0] == 0:
1826 165 storres
            if boundsInterval.endpoints()[1] == 0:
1827 165 storres
                return None
1828 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
1829 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
1830 165 storres
            # The upper bound is a power of two
1831 165 storres
            if binade == l2:
1832 165 storres
                scalingCoeff    = 2^(-binade)
1833 165 storres
                invScalingCoeff = 2^(binade)
1834 165 storres
                scalingOffset   = 1
1835 179 storres
                return \
1836 179 storres
                  ((scalingCoeff * expVar + scalingOffset).function(expVar),
1837 179 storres
                  ((expVar - scalingOffset) * invScalingCoeff).function(expVar))
1838 165 storres
            else:
1839 165 storres
                scalingCoeff    = 2^(-binade-1)
1840 165 storres
                invScalingCoeff = 2^(binade+1)
1841 165 storres
                scalingOffset   = 1
1842 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1843 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1844 165 storres
        # The lower bound is (or should be) negative.
1845 165 storres
        if boundsInterval.endpoints()[1] == 0:
1846 165 storres
            if boundsInterval.endpoints()[0] == 0:
1847 165 storres
                return None
1848 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
1849 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
1850 165 storres
            # The upper bound is a power of two
1851 165 storres
            if binade == l2:
1852 165 storres
                scalingCoeff    = -2^(-binade)
1853 165 storres
                invScalingCoeff = -2^(binade)
1854 165 storres
                scalingOffset   = 1
1855 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1856 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
1857 165 storres
            else:
1858 165 storres
                scalingCoeff    = -2^(-binade-1)
1859 165 storres
                invScalingCoeff = -2^(binade+1)
1860 165 storres
                scalingOffset   = 1
1861 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
1862 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
1863 165 storres
    # General case
1864 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
1865 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
1866 165 storres
    # We allow for a single exception in binade spanning is when the
1867 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
1868 165 storres
    # "inner bound" + 1.
1869 165 storres
    if boundsInterval.endpoints()[0] > 0:
1870 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
1871 165 storres
        if lbBinade != ubBinade:
1872 165 storres
            print "Different binades."
1873 165 storres
            if ubL2 != ubBinade:
1874 165 storres
                print "Not a power of 2."
1875 165 storres
                return None
1876 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1877 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1878 165 storres
                return None
1879 165 storres
    else:
1880 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
1881 165 storres
        if lbBinade != ubBinade:
1882 165 storres
            print "Different binades."
1883 165 storres
            if lbL2 != lbBinade:
1884 165 storres
                print "Not a power of 2."
1885 165 storres
                return None
1886 165 storres
            elif abs(ubBinade - lbBinade) > 1:
1887 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
1888 165 storres
                return None
1889 165 storres
    #print "Lower bound binade:", binade
1890 165 storres
    if boundsInterval.endpoints()[0] > 0:
1891 179 storres
        return \
1892 179 storres
            ((2^(-lbBinade) * expVar).function(expVar),
1893 179 storres
             (2^(lbBinade) * expVar).function(expVar))
1894 165 storres
    else:
1895 179 storres
        return \
1896 179 storres
            ((-(2^(-ubBinade)) * expVar).function(expVar),
1897 179 storres
             (-(2^(ubBinade)) * expVar).function(expVar))
1898 165 storres
"""
1899 165 storres
    # Code sent to attic. Should be the base for a
1900 165 storres
    # "slz_interval_translate_expression" rather than scale.
1901 165 storres
    # Extra control and special cases code  added in
1902 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
1903 165 storres
    # this new function.
1904 62 storres
    # The scaling offset is only used for negative numbers.
1905 151 storres
    # When the absolute value of the lower bound is < 0.
1906 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
1907 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1908 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1909 62 storres
            invScalingCoeff = 1/scalingCoeff
1910 80 storres
            return((scalingCoeff * expVar,
1911 80 storres
                    invScalingCoeff * expVar))
1912 60 storres
        else:
1913 62 storres
            scalingCoeff = \
1914 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
1915 62 storres
            scalingOffset = -3 * scalingCoeff
1916 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1917 80 storres
                    1/scalingCoeff * expVar + 3))
1918 61 storres
    else:
1919 61 storres
        if boundsInterval.endpoints()[0] >= 0:
1920 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
1921 61 storres
            scalingOffset = 0
1922 80 storres
            return((scalingCoeff * expVar,
1923 80 storres
                    1/scalingCoeff * expVar))
1924 61 storres
        else:
1925 62 storres
            scalingCoeff = \
1926 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
1927 62 storres
            scalingOffset =  -3 * scalingCoeff
1928 62 storres
            #scalingOffset = 0
1929 80 storres
            return((scalingCoeff * expVar + scalingOffset,
1930 80 storres
                    1/scalingCoeff * expVar + 3))
1931 165 storres
"""
1932 151 storres
# End slz_interval_scaling_expression
1933 61 storres
1934 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
1935 72 storres
    """
1936 72 storres
    Compute the Sage version of the Taylor polynomial and it's
1937 72 storres
    companion data (interval, center...)
1938 72 storres
    The input parameter is a five elements tuple:
1939 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1940 79 storres
           real ring;
1941 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1942 79 storres
           over a real ring;
1943 72 storres
    - [2]: the interval (as Sollya range);
1944 72 storres
    - [3]: the interval center;
1945 72 storres
    - [4]: the approximation error.
1946 72 storres
1947 218 storres
    The function returns a 5 elements tuple: formed with all the
1948 72 storres
    input elements converted into their Sollya counterpart.
1949 72 storres
    """
1950 233 storres
    #print "Sollya polynomial to convert:",
1951 233 storres
    #pobyso_autoprint(polyRangeCenterErrorSo)
1952 218 storres
    polynomialSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[0])
1953 218 storres
    #print "Polynomial after first conversion: ", pobyso_autoprint(polyRangeCenterErrorSo[1])
1954 218 storres
    polynomialChangedVarSa = pobyso_float_poly_so_sa(polyRangeCenterErrorSo[1])
1955 60 storres
    intervalSa = \
1956 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1957 60 storres
    centerSa = \
1958 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1959 60 storres
    errorSa = \
1960 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1961 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1962 83 storres
    # End slz_interval_and_polynomial_to_sage
1963 62 storres
1964 269 storres
def slz_is_htrn(argument,
1965 269 storres
                function,
1966 269 storres
                targetAccuracy,
1967 269 storres
                targetRF = None,
1968 269 storres
                targetPlusOnePrecRF = None,
1969 269 storres
                quasiExactRF = None):
1970 172 storres
    """
1971 172 storres
      Check if an element (argument) of the domain of function (function)
1972 172 storres
      yields a HTRN case (rounding to next) for the target precision
1973 183 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuracy).
1974 205 storres
1975 205 storres
      The strategy is:
1976 205 storres
      - compute the image at high (quasi-exact) precision;
1977 205 storres
      - round it to nearest to precision;
1978 205 storres
      - round it to exactly to (precision+1), the computed number has two
1979 205 storres
        midpoint neighbors;
1980 205 storres
      - check the distance between these neighbors and the quasi-exact value;
1981 205 storres
        - if none of them is closer than the targetAccuracy, return False,
1982 205 storres
        - else return true.
1983 205 storres
      - Powers of two are a special case when comparing the midpoint in
1984 205 storres
        the 0 direction..
1985 172 storres
    """
1986 183 storres
    ## Arguments filtering.
1987 183 storres
    ## TODO: filter the first argument for consistence.
1988 172 storres
    if targetRF is None:
1989 172 storres
        targetRF = argument.parent()
1990 172 storres
    ## Ditto for the real field holding the midpoints.
1991 172 storres
    if targetPlusOnePrecRF is None:
1992 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1993 183 storres
    ## If no quasiExactField is provided, create a high accuracy RealField.
1994 172 storres
    if quasiExactRF is None:
1995 172 storres
        quasiExactRF = RealField(1536)
1996 195 storres
    function                      = function.function(function.variables()[0])
1997 172 storres
    exactArgument                 = quasiExactRF(argument)
1998 172 storres
    quasiExactValue               = function(exactArgument)
1999 172 storres
    roundedValue                  = targetRF(quasiExactValue)
2000 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
2001 172 storres
    # Upper midpoint.
2002 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
2003 172 storres
    # Lower midpoint.
2004 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
2005 172 storres
    binade                        = slz_compute_binade(roundedValue)
2006 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
2007 172 storres
    #print "Argument:", argument
2008 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
2009 174 storres
    #print "Binade:", binade
2010 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
2011 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
2012 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
2013 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
2014 172 storres
    #print "Upper midpoint:", \
2015 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2016 172 storres
    #print "Rounded value :", \
2017 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
2018 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
2019 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
2020 172 storres
    #print "Lower midpoint:", \
2021 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2022 205 storres
    ## Make quasiExactValue = 0 a special case to move it out of the way.
2023 205 storres
    if quasiExactValue == 0:
2024 205 storres
        return False
2025 205 storres
    ## Begining of the general case : check with the midpoint of
2026 172 storres
    #  greatest absolute value.
2027 172 storres
    if quasiExactValue > 0:
2028 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
2029 172 storres
           binadeCorrectedTargetAccuracy:
2030 183 storres
            #print "Too close to the upper midpoint: ", \
2031 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
2032 172 storres
            #print argument.n().str(base=16, \
2033 172 storres
            #  no_sci=False)
2034 172 storres
            #print "Lower midpoint:", \
2035 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2036 172 storres
            #print "Value         :", \
2037 183 storres
            # quasiExactValue.n(prec=200).str(base=2)
2038 172 storres
            #print "Upper midpoint:", \
2039 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2040 172 storres
            return True
2041 205 storres
    else: # quasiExactValue < 0, the 0 case has been previously filtered out.
2042 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
2043 172 storres
           binadeCorrectedTargetAccuracy:
2044 172 storres
            #print "Too close to the upper midpoint: ", \
2045 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
2046 172 storres
            #print argument.n().str(base=16, \
2047 172 storres
            #  no_sci=False)
2048 172 storres
            #print "Lower midpoint:", \
2049 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2050 172 storres
            #print "Value         :", \
2051 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
2052 172 storres
            #print "Upper midpoint:", \
2053 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2054 172 storres
            #print
2055 172 storres
            return True
2056 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
2057 172 storres
    ## For the midpoint of smaller absolute value,
2058 172 storres
    #  split cases with the powers of 2.
2059 172 storres
    if sno_abs_is_power_of_two(roundedValue):
2060 172 storres
        if quasiExactValue > 0:
2061 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - 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
        else:
2072 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
2073 172 storres
              binadeCorrectedTargetAccuracy / 2:
2074 172 storres
                #print "Lower midpoint:", \
2075 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2076 172 storres
                #print "Value         :",
2077 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
2078 172 storres
                #print "Upper midpoint:",
2079 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2080 172 storres
                #print
2081 172 storres
                return True
2082 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
2083 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
2084 172 storres
          #  smaller absolute value.
2085 172 storres
        if quasiExactValue > 0:
2086 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - 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
        else: # quasiExactValue <= 0
2097 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
2098 172 storres
              binadeCorrectedTargetAccuracy:
2099 172 storres
                #print "Lower midpoint:", \
2100 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2101 172 storres
                #print "Value         :", \
2102 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
2103 172 storres
                #print "Upper midpoint:", \
2104 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
2105 172 storres
                #print
2106 172 storres
                return True
2107 172 storres
    #print "distance to the upper midpoint:", \
2108 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
2109 172 storres
    #print "distance to the lower midpoint:", \
2110 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
2111 172 storres
    return False
2112 172 storres
# End slz_is_htrn
2113 247 storres
#
2114 247 storres
def slz_pm1():
2115 247 storres
    """
2116 253 storres
    Compute a uniform RV in {-1, 1} (not zero).
2117 247 storres
    """
2118 247 storres
    ## function getrandbits(N) generates a long int with N random bits.
2119 247 storres
    return getrandbits(1) * 2-1
2120 247 storres
# End slz_pm1.
2121 247 storres
#
2122 247 storres
def slz_random_proj_pm1(r, c):
2123 247 storres
    """
2124 247 storres
    r x c matrix with \pm 1 ({-1, 1}) 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_pm1()
2130 247 storres
    return M
2131 247 storres
# End random_proj_pm1.
2132 247 storres
#
2133 247 storres
def slz_random_proj_uniform(n, r, c):
2134 247 storres
    """
2135 247 storres
    r x c integer matrix with uniform n-bit integer coefficients
2136 247 storres
    """
2137 247 storres
    M = matrix(r, c)
2138 247 storres
    for i in range(0, r):
2139 247 storres
        for j in range (0, c):
2140 247 storres
            M[i,j] = slz_uniform(n)
2141 247 storres
    return M
2142 247 storres
# End slz_random_proj_uniform.
2143 247 storres
#
2144 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
2145 80 storres
                                                precision,
2146 80 storres
                                                targetHardnessToRound,
2147 80 storres
                                                variable1,
2148 80 storres
                                                variable2):
2149 80 storres
    """
2150 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
2151 90 storres
     with the Coppersmith method.
2152 80 storres
    A the same time it computes :
2153 80 storres
    - 2^K (N);
2154 90 storres
    - 2^k (bound on the second variable)
2155 80 storres
    - lcm
2156 90 storres
2157 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
2158 90 storres
                         variables.
2159 90 storres
    :param precision: the precision of the floating-point coefficients.
2160 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
2161 90 storres
    :param variable1: the first variable of the polynomial (an expression).
2162 90 storres
    :param variable2: the second variable of the polynomial (an expression).
2163 90 storres
2164 90 storres
    :returns: a 4 elements tuple:
2165 90 storres
                - the polynomial;
2166 91 storres
                - the modulus (N);
2167 91 storres
                - the t bound;
2168 90 storres
                - the lcm used to compute the integral coefficients and the
2169 90 storres
                  module.
2170 80 storres
    """
2171 80 storres
    # Create a new integer polynomial ring.
2172 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
2173 80 storres
    # Coefficients are issued in the increasing power order.
2174 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
2175 91 storres
    # Print the reversed list for debugging.
2176 179 storres
    #print
2177 179 storres
    #print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
2178 94 storres
    # Build the list of number we compute the lcm of.
2179 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
2180 179 storres
    #print "Coefficient denominators:", coefficientDenominators
2181 80 storres
    coefficientDenominators.append(2^precision)
2182 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
2183 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
2184 80 storres
    # Compute the expression corresponding to the new polynomial
2185 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
2186 91 storres
    #print coefficientNumerators
2187 80 storres
    polynomialExpression = 0
2188 80 storres
    power = 0
2189 170 storres
    # Iterate over two lists at the same time, stop when the shorter
2190 170 storres
    # (is this case coefficientsNumerators) is
2191 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
2192 170 storres
    # of variable1.
2193 80 storres
    for numerator, denominator in \
2194 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
2195 80 storres
        multiplicator = leastCommonMultiple / denominator
2196 80 storres
        newCoefficient = numerator * multiplicator
2197 80 storres
        polynomialExpression += newCoefficient * variable1^power
2198 80 storres
        power +=1
2199 80 storres
    polynomialExpression += - variable2
2200 80 storres
    return (IP(polynomialExpression),
2201 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
2202 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
2203 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
2204 91 storres
            leastCommonMultiple) # If we want to make test computations.
2205 80 storres
2206 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
2207 79 storres
2208 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
2209 79 storres
                                          precision):
2210 79 storres
    """
2211 79 storres
    Makes a variable substitution into the input polynomial so that the output
2212 79 storres
    polynomial can take integer arguments.
2213 79 storres
    All variables of the input polynomial "have precision p". That is to say
2214 103 storres
    that they are rationals with denominator == 2^(precision - 1):
2215 103 storres
    x = y/2^(precision - 1).
2216 79 storres
    We "incorporate" these denominators into the coefficients with,
2217 79 storres
    respectively, the "right" power.
2218 79 storres
    """
2219 79 storres
    polynomialField = ratPolyOfRat.parent()
2220 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
2221 91 storres
    #print "The polynomial field is:", polynomialField
2222 79 storres
    return \
2223 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
2224 79 storres
                                   polynomialVariable/2^(precision-1)}))
2225 79 storres
2226 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
2227 79 storres
2228 177 storres
def slz_reduce_and_test_base(matrixToReduce,
2229 177 storres
                             nAtAlpha,
2230 177 storres
                             monomialsCountSqrt):
2231 177 storres
    """
2232 177 storres
    Reduces the basis, tests the Coppersmith condition and returns
2233 177 storres
    a list of rows that comply with the condition.
2234 177 storres
    """
2235 177 storres
    ccComplientRowsList = []
2236 177 storres
    reducedMatrix = matrixToReduce.LLL(None)
2237 177 storres
    if not reducedMatrix.is_LLL_reduced():
2238 177 storres
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
2239 177 storres
    else:
2240 177 storres
        print "reducedMatrix is actually reduced."
2241 177 storres
    print "N^alpha:", nAtAlpha.n()
2242 177 storres
    rowIndex = 0
2243 177 storres
    for row in reducedMatrix.rows():
2244 177 storres
        l2Norm = row.norm(2)
2245 177 storres
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
2246 177 storres
                monomialsCountSqrt.n(), ". Is vector OK?",
2247 177 storres
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
2248 177 storres
            ccComplientRowsList.append(row)
2249 177 storres
            print "True"
2250 177 storres
        else:
2251 177 storres
            print "False"
2252 177 storres
    # End for
2253 177 storres
    return ccComplientRowsList
2254 177 storres
# End slz_reduce_and_test_base
2255 115 storres
2256 247 storres
def slz_reduce_lll_proj(matToReduce, n):
2257 247 storres
    """
2258 247 storres
    Compute the transformation matrix that realizes an LLL reduction on
2259 247 storres
    the random uniform projected matrix.
2260 247 storres
    Return both the initial matrix "reduced" by the transformation matrix and
2261 247 storres
    the transformation matrix itself.
2262 247 storres
    """
2263 247 storres
    ## Compute the projected matrix.
2264 249 storres
    """
2265 249 storres
    # Random matrix elements {-2^(n-1),...,0,...,2^(n-1)-1}.
2266 247 storres
    matProjector = slz_random_proj_uniform(n,
2267 247 storres
                                           matToReduce.ncols(),
2268 247 storres
                                           matToReduce.nrows())
2269 249 storres
    """
2270 249 storres
    # Random matrix elements in {-1,0,1}.
2271 249 storres
    matProjector = slz_random_proj_pm1(matToReduce.ncols(),
2272 249 storres
                                       matToReduce.nrows())
2273 247 storres
    matProjected = matToReduce * matProjector
2274 247 storres
    ## Build the argument matrix for LLL in such a way that the transformation
2275 247 storres
    #  matrix is also returned. This matrix is obtained at almost no extra
2276 247 storres
    # cost. An identity matrix must be appended to
2277 247 storres
    #  the left of the initial matrix. The transformation matrix will
2278 247 storres
    # will be recovered at the same location from the returned matrix .
2279 247 storres
    idMat = identity_matrix(matProjected.nrows())
2280 247 storres
    augmentedMatToReduce = idMat.augment(matProjected)
2281 247 storres
    reducedProjMat = \
2282 247 storres
        augmentedMatToReduce.LLL(algorithm='fpLLL:wrapper')
2283 247 storres
    ## Recover the transformation matrix (the left part of the reduced matrix).
2284 247 storres
    #  We discard the reduced matrix itself.
2285 247 storres
    transMat = reducedProjMat.submatrix(0,
2286 247 storres
                                        0,
2287 247 storres
                                        reducedProjMat.nrows(),
2288 247 storres
                                        reducedProjMat.nrows())
2289 247 storres
    ## Return the initial matrix "reduced" and the transformation matrix tuple.
2290 247 storres
    return (transMat * matToReduce, transMat)
2291 247 storres
# End  slz_reduce_lll_proj.
2292 247 storres
#
2293 229 storres
def slz_resultant(poly1, poly2, elimVar, debug = False):
2294 205 storres
    """
2295 205 storres
    Compute the resultant for two polynomials for a given variable
2296 205 storres
    and return the (poly1, poly2, resultant) if the resultant
2297 205 storres
    is not 0.
2298 205 storres
    Return () otherwise.
2299 205 storres
    """
2300 205 storres
    polynomialRing0    = poly1.parent()
2301 205 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
2302 213 storres
    if resultantInElimVar is None:
2303 229 storres
        if debug:
2304 229 storres
            print poly1
2305 229 storres
            print poly2
2306 229 storres
            print "have GCD = ", poly1.gcd(poly2)
2307 213 storres
        return None
2308 205 storres
    if resultantInElimVar.is_zero():
2309 229 storres
        if debug:
2310 229 storres
            print poly1
2311 229 storres
            print poly2
2312 229 storres
            print "have GCD = ", poly1.gcd(poly2)
2313 205 storres
        return None
2314 205 storres
    else:
2315 229 storres
        if debug:
2316 229 storres
            print poly1
2317 229 storres
            print poly2
2318 229 storres
            print "have resultant in t = ", resultantInElimVar
2319 205 storres
        return resultantInElimVar
2320 205 storres
# End slz_resultant.
2321 205 storres
#
2322 177 storres
def slz_resultant_tuple(poly1, poly2, elimVar):
2323 179 storres
    """
2324 179 storres
    Compute the resultant for two polynomials for a given variable
2325 179 storres
    and return the (poly1, poly2, resultant) if the resultant
2326 180 storres
    is not 0.
2327 179 storres
    Return () otherwise.
2328 179 storres
    """
2329 181 storres
    polynomialRing0    = poly1.parent()
2330 177 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
2331 180 storres
    if resultantInElimVar.is_zero():
2332 177 storres
        return ()
2333 177 storres
    else:
2334 177 storres
        return (poly1, poly2, resultantInElimVar)
2335 177 storres
# End slz_resultant_tuple.
2336 177 storres
#
2337 247 storres
def slz_uniform(n):
2338 247 storres
    """
2339 253 storres
    Compute a uniform RV in [-2^(n-1), 2^(n-1)-1] (zero is included).
2340 247 storres
    """
2341 247 storres
    ## function getrandbits(n) generates a long int with n random bits.
2342 247 storres
    return getrandbits(n) - 2^(n-1)
2343 247 storres
# End slz_uniform.
2344 247 storres
#
2345 246 storres
sys.stderr.write("\t...sageSLZ loaded\n")