Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (90,12 ko)

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