Statistiques
| Révision :

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

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