Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (95,57 ko)

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