Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (59 ko)

1 115 storres
r"""
2 115 storres
Sage core functions needed for the implementation of SLZ.
3 90 storres
4 115 storres
AUTHORS:
5 115 storres
- S.T. (2013-08): initial version
6 90 storres
7 115 storres
Examples:
8 119 storres
9 119 storres
TODO::
10 90 storres
"""
11 87 storres
print "sageSLZ loading..."
12 115 storres
#
13 165 storres
def slz_compute_binade(number):
14 165 storres
    """"
15 165 storres
    For a given number, compute the "binade" that is integer m such that
16 165 storres
    2^m <= number < 2^(m+1). If number == 0 return None.
17 165 storres
    """
18 165 storres
    # Checking the parameter.
19 172 storres
    # The exception construction is used to detect if number is a RealNumber
20 165 storres
    # since not all numbers have
21 165 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
22 165 storres
    try:
23 165 storres
        classTree = [number.__class__] + number.mro()
24 172 storres
        # If the number is not a RealNumber (or offspring thereof) try
25 165 storres
        # to transform it.
26 165 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
27 165 storres
            numberAsRR = RR(number)
28 165 storres
        else:
29 165 storres
            numberAsRR = number
30 165 storres
    except AttributeError:
31 165 storres
        return None
32 165 storres
    # Zero special case.
33 165 storres
    if numberAsRR == 0:
34 165 storres
        return RR(-infinity)
35 165 storres
    else:
36 176 storres
        realField           = numberAsRR.parent()
37 176 storres
        numberLog2          = numberAsRR.abs().log2()
38 176 storres
        floorNumberLog2     = floor(numberLog2)
39 176 storres
        ## Do not get caught by rounding of log2() both ways.
40 176 storres
        ## When numberLog2 is an integer, compare numberAsRR
41 176 storres
        #  with 2^numberLog2.
42 176 storres
        if floorNumberLog2 == numberLog2:
43 176 storres
            if numberAsRR.abs() < realField(2^floorNumberLog2):
44 176 storres
                return floorNumberLog2 - 1
45 176 storres
            else:
46 176 storres
                return floorNumberLog2
47 176 storres
        else:
48 176 storres
            return floorNumberLog2
49 165 storres
# End slz_compute_binade
50 165 storres
51 115 storres
#
52 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
53 119 storres
    """
54 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
55 121 storres
56 121 storres
    NOTE::
57 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
58 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
59 125 storres
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
60 125 storres
        this case from that of "really" invalid arguments.
61 121 storres
62 119 storres
    """
63 121 storres
    # Check the parameters.
64 125 storres
    # RealNumbers or RealNumber offspring only.
65 165 storres
    # The exception construction is necessary since not all objects have
66 125 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
67 124 storres
    try:
68 124 storres
        classTree = [number.__class__] + number.mro()
69 124 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
70 124 storres
            return None
71 124 storres
    except AttributeError:
72 121 storres
        return None
73 121 storres
    # Non zero negative integers only for emin.
74 121 storres
    if emin >= 0 or int(emin) != emin:
75 121 storres
        return None
76 121 storres
    # Non zero positive integers only for emax.
77 121 storres
    if emax <= 0 or int(emax) != emax:
78 121 storres
        return None
79 121 storres
    precision = number.precision()
80 121 storres
    RF  = RealField(precision)
81 125 storres
    if number == 0:
82 125 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
83 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
84 121 storres
    # when computing number.log2().
85 121 storres
    RRF = RealField(max(2048, 2 * precision))
86 121 storres
    # number = 0 special case, the binade bounds are
87 121 storres
    # [0, 2^emin - 2^(emin-precision)]
88 121 storres
    # Begin general case
89 119 storres
    l2 = RRF(number).abs().log2()
90 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
91 121 storres
    if l2 >= emax + 1:
92 121 storres
        if number > 0:
93 125 storres
            return (RF(2^(emax+1)), RF(+infinity) )
94 121 storres
        else:
95 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
96 165 storres
    # Regular case cont'd.
97 119 storres
    offset = int(l2)
98 121 storres
    # number.abs() >= 1.
99 119 storres
    if l2 >= 0:
100 119 storres
        if number >= 0:
101 119 storres
            lb = RF(2^offset)
102 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
103 119 storres
        else: #number < 0
104 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
105 119 storres
            ub = -RF(2^offset)
106 121 storres
    else: # log2 < 0, number.abs() < 1.
107 119 storres
        if l2 < emin: # Denormal
108 121 storres
           # print "Denormal:", l2
109 119 storres
            if number >= 0:
110 119 storres
                lb = RF(0)
111 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
112 119 storres
            else: # number <= 0
113 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
114 119 storres
                ub = RF(0)
115 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
116 119 storres
            if number >= 0:
117 121 storres
                if int(l2) == l2:
118 121 storres
                    lb = RF(2^(offset))
119 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
120 121 storres
                else:
121 121 storres
                    lb = RF(2^(offset-1))
122 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
123 119 storres
            else: # number < 0
124 121 storres
                if int(l2) == l2: # Binade limit.
125 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
126 121 storres
                    ub = -RF(2^(offset))
127 121 storres
                else:
128 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
129 121 storres
                    ub = -RF(2^(offset-1))
130 121 storres
        else: # l2== emin, number == +/-2^emin
131 119 storres
            if number >= 0:
132 119 storres
                lb = RF(2^(offset))
133 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
134 119 storres
            else: # number < 0
135 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
136 119 storres
                ub = -RF(2^(offset))
137 119 storres
    return (lb, ub)
138 119 storres
# End slz_compute_binade_bounds
139 119 storres
#
140 123 storres
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
141 123 storres
                                                 alpha,
142 123 storres
                                                 N,
143 123 storres
                                                 iBound,
144 123 storres
                                                 tBound):
145 123 storres
    """
146 123 storres
    For a given set of arguments (see below), compute a list
147 123 storres
    of "reduced polynomials" that could be used to compute roots
148 123 storres
    of the inputPolynomial.
149 124 storres
    INPUT:
150 124 storres
151 124 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
152 124 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
153 124 storres
    - "N" -- the modulus;
154 124 storres
    - "iBound" -- the bound on the first variable;
155 124 storres
    - "tBound" -- the bound on the second variable.
156 124 storres
157 124 storres
    OUTPUT:
158 124 storres
159 124 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
160 124 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
161 124 storres
    reduced base that comply with the Coppersmith condition.
162 123 storres
    """
163 123 storres
    # Arguments check.
164 123 storres
    if iBound == 0 or tBound == 0:
165 123 storres
        return ()
166 123 storres
    # End arguments check.
167 123 storres
    nAtAlpha = N^alpha
168 123 storres
    ## Building polynomials for matrix.
169 123 storres
    polyRing   = inputPolynomial.parent()
170 123 storres
    # Whatever the 2 variables are actually called, we call them
171 123 storres
    # 'i' and 't' in all the variable names.
172 123 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
173 123 storres
    #print polyVars[0], type(polyVars[0])
174 123 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
175 123 storres
                                              tVariable:tVariable * tBound})
176 123 storres
    polynomialsList = \
177 158 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
178 123 storres
                                             alpha,
179 123 storres
                                             N,
180 123 storres
                                             iBound,
181 123 storres
                                             tBound,
182 123 storres
                                             0)
183 123 storres
    #print "Polynomials list:", polynomialsList
184 123 storres
    ## Building the proto matrix.
185 123 storres
    knownMonomials = []
186 123 storres
    protoMatrix    = []
187 123 storres
    for poly in polynomialsList:
188 123 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
189 123 storres
                                                knownMonomials,
190 123 storres
                                                protoMatrix,
191 123 storres
                                                0)
192 123 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
193 123 storres
    #print matrixToReduce
194 123 storres
    ## Reduction and checking.
195 163 storres
    ## S.T. changed 'fp' to None as of Sage 6.6 complying to
196 163 storres
    #  error message issued when previous code was used.
197 163 storres
    #reducedMatrix = matrixToReduce.LLL(fp='fp')
198 163 storres
    reducedMatrix = matrixToReduce.LLL(fp=None)
199 123 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
200 123 storres
    if not isLLLReduced:
201 157 storres
        return ()
202 123 storres
    monomialsCount     = len(knownMonomials)
203 123 storres
    monomialsCountSqrt = sqrt(monomialsCount)
204 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
205 123 storres
    #print reducedMatrix
206 123 storres
    ## Check the Coppersmith condition for each row and build the reduced
207 123 storres
    #  polynomials.
208 123 storres
    ccReducedPolynomialsList = []
209 123 storres
    for row in reducedMatrix.rows():
210 123 storres
        l2Norm = row.norm(2)
211 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
212 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
213 125 storres
            #print l2Norm.n()
214 123 storres
            ccReducedPolynomial = \
215 123 storres
                slz_compute_reduced_polynomial(row,
216 123 storres
                                               knownMonomials,
217 123 storres
                                               iVariable,
218 123 storres
                                               iBound,
219 123 storres
                                               tVariable,
220 123 storres
                                               tBound)
221 123 storres
            if not ccReducedPolynomial is None:
222 123 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
223 123 storres
        else:
224 125 storres
            #print l2Norm.n() , ">", nAtAlpha
225 123 storres
            pass
226 123 storres
    if len(ccReducedPolynomialsList) < 2:
227 125 storres
        print "Less than 2 Coppersmith condition compliant vectors."
228 123 storres
        return ()
229 125 storres
230 125 storres
    #print ccReducedPolynomialsList
231 123 storres
    return ccReducedPolynomialsList
232 123 storres
# End slz_compute_coppersmith_reduced_polynomials
233 123 storres
234 122 storres
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
235 122 storres
                                                 alpha,
236 122 storres
                                                 N,
237 122 storres
                                                 iBound,
238 122 storres
                                                 tBound):
239 122 storres
    """
240 123 storres
    For a given set of arguments (see below), compute the polynomial modular
241 122 storres
    roots, if any.
242 124 storres
243 122 storres
    """
244 123 storres
    # Arguments check.
245 123 storres
    if iBound == 0 or tBound == 0:
246 123 storres
        return set()
247 123 storres
    # End arguments check.
248 122 storres
    nAtAlpha = N^alpha
249 122 storres
    ## Building polynomials for matrix.
250 122 storres
    polyRing   = inputPolynomial.parent()
251 122 storres
    # Whatever the 2 variables are actually called, we call them
252 122 storres
    # 'i' and 't' in all the variable names.
253 122 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
254 125 storres
    ccReducedPolynomialsList = \
255 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
256 125 storres
                                                     alpha,
257 125 storres
                                                     N,
258 125 storres
                                                     iBound,
259 125 storres
                                                     tBound)
260 125 storres
    if len(ccReducedPolynomialsList) == 0:
261 125 storres
        return set()
262 122 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
263 122 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
264 122 storres
    # Try to mix and match all the polynomial pairs built from the
265 122 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
266 122 storres
    resultantsInITuplesList = []
267 122 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
268 122 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
269 122 storres
                                     len(ccReducedPolynomialsList)):
270 122 storres
            # Compute the resultant in resultants in the
271 122 storres
            # first variable (is it the optimal choice?).
272 122 storres
            resultantInI = \
273 122 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
274 122 storres
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
275 122 storres
            #print "Resultant", resultantInI
276 122 storres
            # Test algebraic independence.
277 122 storres
            if not resultantInI.is_zero():
278 122 storres
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
279 122 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
280 122 storres
                                                 resultantInI))
281 122 storres
    # If no non zero resultant was found: we can't get no algebraically
282 122 storres
    # independent polynomials pair. Give up!
283 122 storres
    if len(resultantsInITuplesList) == 0:
284 123 storres
        return set()
285 123 storres
    #print resultantsInITuplesList
286 122 storres
    # Compute the roots.
287 122 storres
    Zi = ZZ[str(iVariable)]
288 122 storres
    Zt = ZZ[str(tVariable)]
289 122 storres
    polynomialRootsSet = set()
290 122 storres
    # First, solve in the second variable since resultants are in the first
291 122 storres
    # variable.
292 122 storres
    for resultantInITuple in resultantsInITuplesList:
293 122 storres
        tRootsList = Zt(resultantInITuple[2]).roots()
294 122 storres
        # For each tRoot, compute the corresponding iRoots and check
295 123 storres
        # them in the input polynomial.
296 122 storres
        for tRoot in tRootsList:
297 123 storres
            #print "tRoot:", tRoot
298 122 storres
            # Roots returned by root() are (value, multiplicity) tuples.
299 122 storres
            iRootsList = \
300 122 storres
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
301 123 storres
            print iRootsList
302 122 storres
            # The iRootsList can be empty, hence the test.
303 122 storres
            if len(iRootsList) != 0:
304 122 storres
                for iRoot in iRootsList:
305 122 storres
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
306 122 storres
                    # polyEvalModN must be an integer.
307 122 storres
                    if polyEvalModN == int(polyEvalModN):
308 122 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
309 122 storres
    return polynomialRootsSet
310 122 storres
# End slz_compute_integer_polynomial_modular_roots.
311 122 storres
#
312 125 storres
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
313 125 storres
                                                 alpha,
314 125 storres
                                                 N,
315 125 storres
                                                 iBound,
316 125 storres
                                                 tBound):
317 125 storres
    """
318 125 storres
    For a given set of arguments (see below), compute the polynomial modular
319 125 storres
    roots, if any.
320 125 storres
    This version differs in the way resultants are computed.
321 125 storres
    """
322 125 storres
    # Arguments check.
323 125 storres
    if iBound == 0 or tBound == 0:
324 125 storres
        return set()
325 125 storres
    # End arguments check.
326 125 storres
    nAtAlpha = N^alpha
327 125 storres
    ## Building polynomials for matrix.
328 125 storres
    polyRing   = inputPolynomial.parent()
329 125 storres
    # Whatever the 2 variables are actually called, we call them
330 125 storres
    # 'i' and 't' in all the variable names.
331 125 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
332 125 storres
    #print polyVars[0], type(polyVars[0])
333 125 storres
    ccReducedPolynomialsList = \
334 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
335 125 storres
                                                     alpha,
336 125 storres
                                                     N,
337 125 storres
                                                     iBound,
338 125 storres
                                                     tBound)
339 125 storres
    if len(ccReducedPolynomialsList) == 0:
340 125 storres
        return set()
341 125 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
342 125 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
343 125 storres
    # Try to mix and match all the polynomial pairs built from the
344 125 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
345 125 storres
    resultantsInTTuplesList = []
346 125 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
347 125 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
348 125 storres
                                     len(ccReducedPolynomialsList)):
349 125 storres
            # Compute the resultant in resultants in the
350 125 storres
            # first variable (is it the optimal choice?).
351 125 storres
            resultantInT = \
352 125 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
353 125 storres
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
354 125 storres
            #print "Resultant", resultantInT
355 125 storres
            # Test algebraic independence.
356 125 storres
            if not resultantInT.is_zero():
357 125 storres
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
358 125 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
359 125 storres
                                                 resultantInT))
360 125 storres
    # If no non zero resultant was found: we can't get no algebraically
361 125 storres
    # independent polynomials pair. Give up!
362 125 storres
    if len(resultantsInTTuplesList) == 0:
363 125 storres
        return set()
364 125 storres
    #print resultantsInITuplesList
365 125 storres
    # Compute the roots.
366 125 storres
    Zi = ZZ[str(iVariable)]
367 125 storres
    Zt = ZZ[str(tVariable)]
368 125 storres
    polynomialRootsSet = set()
369 125 storres
    # First, solve in the second variable since resultants are in the first
370 125 storres
    # variable.
371 125 storres
    for resultantInTTuple in resultantsInTTuplesList:
372 125 storres
        iRootsList = Zi(resultantInTTuple[2]).roots()
373 125 storres
        # For each iRoot, compute the corresponding tRoots and check
374 125 storres
        # them in the input polynomial.
375 125 storres
        for iRoot in iRootsList:
376 125 storres
            #print "iRoot:", iRoot
377 125 storres
            # Roots returned by root() are (value, multiplicity) tuples.
378 125 storres
            tRootsList = \
379 125 storres
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
380 125 storres
            print tRootsList
381 125 storres
            # The tRootsList can be empty, hence the test.
382 125 storres
            if len(tRootsList) != 0:
383 125 storres
                for tRoot in tRootsList:
384 125 storres
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
385 125 storres
                    # polyEvalModN must be an integer.
386 125 storres
                    if polyEvalModN == int(polyEvalModN):
387 125 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
388 125 storres
    return polynomialRootsSet
389 125 storres
# End slz_compute_integer_polynomial_modular_roots_2.
390 125 storres
#
391 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
392 61 storres
                                        upperBoundSa, approxPrecSa,
393 61 storres
                                        sollyaPrecSa=None):
394 61 storres
    """
395 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
396 61 storres
    a polynomial that approximates the function on a an interval starting
397 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
398 61 storres
    approximates with the expected precision.
399 61 storres
    The interval upper bound is lowered until the expected approximation
400 61 storres
    precision is reached.
401 61 storres
    The polynomial, the bounds, the center of the interval and the error
402 61 storres
    are returned.
403 156 storres
    OUTPUT:
404 124 storres
    A tuple made of 4 Sollya objects:
405 124 storres
    - a polynomial;
406 124 storres
    - an range (an interval, not in the sense of number given as an interval);
407 124 storres
    - the center of the interval;
408 124 storres
    - the maximum error in the approximation of the input functionSo by the
409 124 storres
      output polynomial ; this error <= approxPrecSaS.
410 124 storres
411 61 storres
    """
412 166 storres
    ## Superficial argument check.
413 166 storres
    if lowerBoundSa > upperBoundSa:
414 166 storres
        return None
415 61 storres
    RRR = lowerBoundSa.parent()
416 176 storres
    intervalShrinkConstFactorSa = RRR('0.9')
417 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
418 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
419 61 storres
    currentUpperBoundSa = upperBoundSa
420 61 storres
    currentLowerBoundSa = lowerBoundSa
421 61 storres
    # What we want here is the polynomial without the variable change,
422 61 storres
    # since our actual variable will be x-intervalCenter defined over the
423 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
424 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
425 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
426 61 storres
                                                    currentRangeSo,
427 61 storres
                                                    absoluteErrorTypeSo)
428 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
429 61 storres
    while maxErrorSa > approxPrecSa:
430 166 storres
        print "++Approximation error:", maxErrorSa
431 81 storres
        sollya_lib_clear_obj(polySo)
432 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
433 120 storres
        sollya_lib_clear_obj(maxErrorSo)
434 176 storres
        # Very empirical schrinking factor.
435 176 storres
        shrinkFactorSa = 1 /  (maxErrorSa/approxPrecSa).log2().abs()
436 176 storres
        print "Shrink factor:", shrinkFactorSa, intervalShrinkConstFactorSa
437 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
438 61 storres
        #print "Error ratio: ", errorRatioSa
439 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
440 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
441 81 storres
            #print "Fixed"
442 61 storres
        else:
443 81 storres
            actualShrinkFactorSa = shrinkFactorSa
444 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
445 81 storres
            #print shrinkFactorSa, maxErrorSa
446 101 storres
        #print "Shrink factor", actualShrinkFactorSa
447 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
448 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
449 81 storres
                                   actualShrinkFactorSa
450 71 storres
        #print "Current upper bound:", currentUpperBoundSa
451 61 storres
        sollya_lib_clear_obj(currentRangeSo)
452 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
453 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
454 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
455 86 storres
            print "Can't find an interval."
456 86 storres
            print "Use either or both a higher polynomial degree or a higher",
457 86 storres
            print "internal precision."
458 86 storres
            print "Aborting!"
459 86 storres
            return (None, None, None, None)
460 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
461 61 storres
                                                      currentUpperBoundSa)
462 86 storres
        # print "New interval:",
463 86 storres
        # pobyso_autoprint(currentRangeSo)
464 120 storres
        #print "Second Taylor expansion call."
465 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
466 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
467 61 storres
                                                        currentRangeSo,
468 61 storres
                                                        absoluteErrorTypeSo)
469 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
470 85 storres
        #print "Max errorSo:",
471 85 storres
        #pobyso_autoprint(maxErrorSo)
472 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
473 85 storres
        #print "Max errorSa:", maxErrorSa
474 85 storres
        #print "Sollya prec:",
475 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
476 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
477 176 storres
    return (polySo, currentRangeSo, intervalCenterSo, maxErrorSo)
478 81 storres
# End slz_compute_polynomial_and_interval
479 61 storres
480 122 storres
def slz_compute_reduced_polynomial(matrixRow,
481 98 storres
                                    knownMonomials,
482 106 storres
                                    var1,
483 98 storres
                                    var1Bound,
484 106 storres
                                    var2,
485 99 storres
                                    var2Bound):
486 98 storres
    """
487 125 storres
    Compute a polynomial from a single reduced matrix row.
488 122 storres
    This function was introduced in order to avoid the computation of the
489 125 storres
    all the polynomials  from the full matrix (even those built from rows
490 125 storres
    that do no verify the Coppersmith condition) as this may involves
491 152 storres
    expensive operations over (large) integers.
492 122 storres
    """
493 122 storres
    ## Check arguments.
494 122 storres
    if len(knownMonomials) == 0:
495 122 storres
        return None
496 122 storres
    # varNounds can be zero since 0^0 returns 1.
497 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
498 122 storres
        return None
499 122 storres
    ## Initialisations.
500 122 storres
    polynomialRing = knownMonomials[0].parent()
501 122 storres
    currentPolynomial = polynomialRing(0)
502 123 storres
    # TODO: use zip instead of indices.
503 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
504 122 storres
        currentCoefficient = matrixRow[colIndex]
505 122 storres
        if currentCoefficient != 0:
506 122 storres
            #print "Current coefficient:", currentCoefficient
507 122 storres
            currentMonomial = knownMonomials[colIndex]
508 122 storres
            #print "Monomial as multivariate polynomial:", \
509 122 storres
            #currentMonomial, type(currentMonomial)
510 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
511 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
512 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
513 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
514 122 storres
            if degreeInVar1 > 0:
515 122 storres
                currentCoefficient = \
516 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
517 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
518 122 storres
                #print "Current coefficient(1)", currentCoefficient
519 122 storres
            if degreeInVar2 > 0:
520 122 storres
                currentCoefficient = \
521 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
522 122 storres
                #print "Current coefficient(2)", currentCoefficient
523 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
524 122 storres
            #                                    currentMonomial)
525 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
526 122 storres
            #print "Current polynomial:", currentPolynomial
527 122 storres
        # End if
528 122 storres
    # End for colIndex.
529 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
530 122 storres
    return(currentPolynomial)
531 122 storres
# End slz_compute_reduced_polynomial
532 122 storres
#
533 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
534 122 storres
                                        knownMonomials,
535 122 storres
                                        var1,
536 122 storres
                                        var1Bound,
537 122 storres
                                        var2,
538 122 storres
                                        var2Bound):
539 122 storres
    """
540 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
541 122 storres
    """
542 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
543 122 storres
                                                knownMonomials,
544 122 storres
                                                var1,
545 122 storres
                                                var1Bound,
546 122 storres
                                                var2,
547 122 storres
                                                var2Bound)
548 122 storres
    )
549 177 storres
#
550 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
551 152 storres
                                         knownMonomials,
552 152 storres
                                         var1,
553 152 storres
                                         var1Bound,
554 152 storres
                                         var2,
555 152 storres
                                         var2Bound):
556 122 storres
    """
557 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
558 98 storres
    from the bounds of each variable, compute the corresponding polynomials
559 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
560 99 storres
561 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
562 172 storres
    They set the polynomial type of the output polynomials in list.
563 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
564 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
565 152 storres
                           build the polynomials;
566 152 storres
    @param var1:           the first variable (of the "right" type);
567 152 storres
    @param var1Bound:      the first variable bound;
568 152 storres
    @param var2:           the second variable (of the "right" type);
569 152 storres
    @param var2Bound:      the second variable bound.
570 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
571 152 storres
             and scaled down with the bounds
572 98 storres
    """
573 99 storres
574 98 storres
    # TODO: check input arguments.
575 98 storres
    reducedPolynomials = []
576 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
577 98 storres
    for matrixRow in reducedMatrix.rows():
578 102 storres
        currentPolynomial = 0
579 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
580 98 storres
            currentCoefficient = matrixRow[colIndex]
581 106 storres
            if currentCoefficient != 0:
582 106 storres
                #print "Current coefficient:", currentCoefficient
583 106 storres
                currentMonomial = knownMonomials[colIndex]
584 106 storres
                parentRing = currentMonomial.parent()
585 106 storres
                #print "Monomial as multivariate polynomial:", \
586 106 storres
                #currentMonomial, type(currentMonomial)
587 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
588 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
589 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
590 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
591 106 storres
                if degreeInVar1 > 0:
592 167 storres
                    currentCoefficient /= var1Bound^degreeInVar1
593 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
594 106 storres
                    #print "Current coefficient(1)", currentCoefficient
595 106 storres
                if degreeInVar2 > 0:
596 167 storres
                    currentCoefficient /= var2Bound^degreeInVar2
597 106 storres
                    #print "Current coefficient(2)", currentCoefficient
598 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
599 106 storres
                #                                    currentMonomial)
600 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
601 168 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
602 168 storres
                    #print "!!!! constant term !!!!"
603 106 storres
                #print "Current polynomial:", currentPolynomial
604 106 storres
            # End if
605 106 storres
        # End for colIndex.
606 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
607 99 storres
        reducedPolynomials.append(currentPolynomial)
608 98 storres
    return reducedPolynomials
609 177 storres
# End slz_compute_reduced_polynomials_list.
610 98 storres
611 177 storres
def slz_compute_reduced_polynomials_list_from_rows(rowsList,
612 177 storres
                                                   knownMonomials,
613 177 storres
                                                   var1,
614 177 storres
                                                   var1Bound,
615 177 storres
                                                   var2,
616 177 storres
                                                   var2Bound):
617 177 storres
    """
618 177 storres
    From a list of rows, holding the coefficients, from a monomials list,
619 177 storres
    from the bounds of each variable, compute the corresponding polynomials
620 177 storres
    scaled back by dividing by the "right" powers of the variables bounds.
621 177 storres
622 177 storres
    The elements in knownMonomials must be of the "right" polynomial type.
623 177 storres
    They set the polynomial type of the output polynomials in list.
624 177 storres
    @param rowsList:       the reduced matrix as output from LLL;
625 177 storres
    @param kwnonMonomials: the ordered list of the monomials used to
626 177 storres
                           build the polynomials;
627 177 storres
    @param var1:           the first variable (of the "right" type);
628 177 storres
    @param var1Bound:      the first variable bound;
629 177 storres
    @param var2:           the second variable (of the "right" type);
630 177 storres
    @param var2Bound:      the second variable bound.
631 177 storres
    @return: a list of polynomials obtained with the reduced coefficients
632 177 storres
             and scaled down with the bounds
633 177 storres
    """
634 177 storres
635 177 storres
    # TODO: check input arguments.
636 177 storres
    reducedPolynomials = []
637 177 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
638 177 storres
    for matrixRow in rowsList:
639 177 storres
        currentPolynomial = 0
640 177 storres
        for colIndex in xrange(0, len(knownMonomials)):
641 177 storres
            currentCoefficient = matrixRow[colIndex]
642 177 storres
            if currentCoefficient != 0:
643 177 storres
                #print "Current coefficient:", currentCoefficient
644 177 storres
                currentMonomial = knownMonomials[colIndex]
645 177 storres
                parentRing = currentMonomial.parent()
646 177 storres
                #print "Monomial as multivariate polynomial:", \
647 177 storres
                #currentMonomial, type(currentMonomial)
648 177 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
649 177 storres
                #print "Degree in var", var1, ":", degreeInVar1
650 177 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
651 177 storres
                #print "Degree in var", var2, ":", degreeInVar2
652 177 storres
                if degreeInVar1 > 0:
653 177 storres
                    currentCoefficient /= var1Bound^degreeInVar1
654 177 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
655 177 storres
                    #print "Current coefficient(1)", currentCoefficient
656 177 storres
                if degreeInVar2 > 0:
657 177 storres
                    currentCoefficient /= var2Bound^degreeInVar2
658 177 storres
                    #print "Current coefficient(2)", currentCoefficient
659 177 storres
                #print "Current reduced monomial:", (currentCoefficient * \
660 177 storres
                #                                    currentMonomial)
661 177 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
662 177 storres
                #if degreeInVar1 == 0 and degreeInVar2 == 0:
663 177 storres
                    #print "!!!! constant term !!!!"
664 177 storres
                #print "Current polynomial:", currentPolynomial
665 177 storres
            # End if
666 177 storres
        # End for colIndex.
667 177 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
668 177 storres
        reducedPolynomials.append(currentPolynomial)
669 177 storres
    return reducedPolynomials
670 177 storres
# End slz_compute_reduced_polynomials_list_from_rows.
671 177 storres
#
672 114 storres
def slz_compute_scaled_function(functionSa,
673 114 storres
                                lowerBoundSa,
674 114 storres
                                upperBoundSa,
675 156 storres
                                floatingPointPrecSa,
676 156 storres
                                debug=False):
677 72 storres
    """
678 72 storres
    From a function, compute the scaled function whose domain
679 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
680 72 storres
    Return a tuple:
681 72 storres
    [0]: the scaled function
682 72 storres
    [1]: the scaled domain lower bound
683 72 storres
    [2]: the scaled domain upper bound
684 72 storres
    [3]: the scaled image lower bound
685 72 storres
    [4]: the scaled image upper bound
686 72 storres
    """
687 177 storres
    ## The variable can be called anything.
688 80 storres
    x = functionSa.variables()[0]
689 72 storres
    # Scalling the domain -> [1,2[.
690 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
691 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
692 166 storres
    (invDomainScalingExpressionSa, domainScalingExpressionSa) = \
693 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
694 156 storres
    if debug:
695 156 storres
        print "domainScalingExpression for argument :", \
696 156 storres
        invDomainScalingExpressionSa
697 156 storres
        print "f: ", f
698 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
699 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
700 177 storres
    #domainScalingFunction(x) = invDomainScalingExpressionSa
701 177 storres
    domainScalingFunction = invDomainScalingExpressionSa.function(x)
702 151 storres
    scaledLowerBoundSa = \
703 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
704 151 storres
    scaledUpperBoundSa = \
705 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
706 156 storres
    if debug:
707 156 storres
        print 'ff:', ff, "- Domain:", scaledLowerBoundSa, \
708 156 storres
              scaledUpperBoundSa
709 72 storres
    #
710 72 storres
    # Scalling the image -> [1,2[.
711 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
712 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
713 72 storres
    if flbSa <= fubSa: # Increasing
714 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
715 72 storres
    else: # Decreasing
716 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
717 156 storres
    if debug:
718 156 storres
        print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
719 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
720 166 storres
    (invImageScalingExpressionSa,imageScalingExpressionSa) = \
721 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
722 156 storres
    if debug:
723 156 storres
        print "imageScalingExpression for argument :", \
724 156 storres
              invImageScalingExpressionSa
725 72 storres
    iis = invImageScalingExpressionSa.function(x)
726 72 storres
    fff = iis.subs({x:ff})
727 156 storres
    if debug:
728 156 storres
        print "fff:", fff,
729 156 storres
        print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
730 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
731 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
732 151 storres
# End slz_compute_scaled_function
733 72 storres
734 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
735 79 storres
    # Create a polynomial over the rationals.
736 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
737 79 storres
    return(polynomialRing(polyOfFloat))
738 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
739 81 storres
740 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
741 63 storres
                                      lowerBoundSa,
742 60 storres
                                      upperBoundSa, floatingPointPrecSa,
743 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
744 60 storres
    """
745 60 storres
    Under the assumption that:
746 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
747 60 storres
    - lowerBound and upperBound belong to the same binade.
748 60 storres
    from a:
749 60 storres
    - function;
750 60 storres
    - a degree
751 60 storres
    - a pair of bounds;
752 60 storres
    - the floating-point precision we work on;
753 60 storres
    - the internal Sollya precision;
754 64 storres
    - the requested approximation error
755 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
756 61 storres
    It return a list of tuples, each made of:
757 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
758 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
759 61 storres
    - the approximation interval;
760 72 storres
    - the center, x0, of the interval;
761 61 storres
    - the corresponding approximation error.
762 100 storres
    TODO: fix endless looping for some parameters sets.
763 60 storres
    """
764 120 storres
    resultArray = []
765 101 storres
    # Set Sollya to the necessary internal precision.
766 120 storres
    precChangedSa = False
767 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
768 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
769 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
770 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
771 120 storres
        precChangedSa = True
772 101 storres
    #
773 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
774 101 storres
    # Scaled function: [1=,2] -> [1,2].
775 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
776 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
777 115 storres
                slz_compute_scaled_function(functionSa,                       \
778 115 storres
                                            lowerBoundSa,                     \
779 115 storres
                                            upperBoundSa,                     \
780 80 storres
                                            floatingPointPrecSa)
781 166 storres
    # In case bounds were in the negative real one may need to
782 166 storres
    # switch scaled bounds.
783 166 storres
    if scaledLowerBoundSa > scaledUpperBoundSa:
784 166 storres
        scaledLowerBoundSa, scaledUpperBoundSa = \
785 166 storres
            scaledUpperBoundSa, scaledLowerBoundSa
786 166 storres
        #print "Switching!"
787 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
788 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
789 159 storres
    functionSo = \
790 159 storres
      pobyso_parse_string_sa_so(fff._assume_str().replace('_SAGE_VAR_', ''))
791 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
792 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
793 61 storres
                                                  scaledUpperBoundSa)
794 176 storres
795 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
796 60 storres
                                              upperBoundSa.parent().precision()))
797 176 storres
    currentScaledLowerBoundSa = scaledLowerBoundSa
798 176 storres
    currentScaledUpperBoundSa = scaledUpperBoundSa
799 176 storres
    while True:
800 176 storres
        ## Compute the first Taylor expansion.
801 176 storres
        print "Computing a Taylor expansion..."
802 176 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
803 176 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
804 176 storres
                                        currentScaledLowerBoundSa,
805 176 storres
                                        currentScaledUpperBoundSa,
806 176 storres
                                        approxPrecSa, internalSollyaPrecSa)
807 176 storres
        print "...done."
808 176 storres
        ## If slz_compute_polynomial_and_interval fails, it returns None.
809 176 storres
        #  This value goes to the first variable: polySo. Other variables are
810 176 storres
        #  not assigned and should not be tested.
811 176 storres
        if polySo is None:
812 176 storres
            print "slz_get_intervals_and_polynomials: Aborting and returning None!"
813 176 storres
            if precChangedSa:
814 176 storres
                pobyso_set_prec_so_so(currentSollyaPrecSo)
815 176 storres
                sollya_lib_clear_obj(currentSollyaPrecSo)
816 176 storres
            sollya_lib_clear_obj(functionSo)
817 176 storres
            sollya_lib_clear_obj(degreeSo)
818 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
819 176 storres
            return None
820 176 storres
        ## Add to the result array.
821 176 storres
        ### Change variable stuff in Sollya x -> x0-x.
822 176 storres
        changeVarExpressionSo = \
823 176 storres
            sollya_lib_build_function_sub( \
824 176 storres
                              sollya_lib_build_function_free_variable(),
825 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
826 176 storres
        polyVarChangedSo = \
827 176 storres
                    sollya_lib_evaluate(polySo, changeVarExpressionSo)
828 176 storres
        #### Get rid of the variable change Sollya stuff.
829 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
830 176 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo,
831 101 storres
                            intervalCenterSo, maxErrorSo))
832 176 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
833 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
834 176 storres
        print "Computed approximation error:", errorSa.n(digits=10)
835 176 storres
        # If the error and interval are OK a the first try, just return.
836 176 storres
        if (boundsSa.endpoints()[1] >= scaledUpperBoundSa) and \
837 176 storres
            (errorSa <= approxPrecSa):
838 176 storres
            if precChangedSa:
839 176 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
840 176 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
841 176 storres
            sollya_lib_clear_obj(functionSo)
842 176 storres
            sollya_lib_clear_obj(degreeSo)
843 176 storres
            sollya_lib_clear_obj(scaledBoundsSo)
844 101 storres
            #print "Approximation error:", errorSa
845 176 storres
            return resultArray
846 176 storres
        ## The returned interval upper bound does not reach the requested upper
847 176 storres
        #  upper bound: compute the next upper bound.
848 176 storres
        ## The following ratio is always >= 1. If errorSa, we may want to
849 176 storres
        #  enlarge the interval
850 81 storres
        currentErrorRatio = approxPrecSa / errorSa
851 176 storres
        ## --|--------------------------------------------------------------|--
852 176 storres
        #  --|--------------------|--------------------------------------------
853 176 storres
        #  --|----------------------------|------------------------------------
854 176 storres
        ## Starting point for the next upper bound.
855 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
856 101 storres
        # Compute the increment.
857 176 storres
        newBoundsWidthSa = \
858 176 storres
                        ((currentErrorRatio.log() / 10) + 1) * boundsWidthSa
859 176 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
860 176 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1] + newBoundsWidthSa
861 176 storres
        # Take into account the original interval upper bound.
862 176 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
863 176 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
864 176 storres
        if currentScaledUpperBoundSa == currentScaledLowerBoundSa:
865 85 storres
            print "Can't shrink the interval anymore!"
866 85 storres
            print "You should consider increasing the Sollya internal precision"
867 85 storres
            print "or the polynomial degree."
868 85 storres
            print "Giving up!"
869 176 storres
            if precChangedSa:
870 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
871 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
872 85 storres
            sollya_lib_clear_obj(functionSo)
873 85 storres
            sollya_lib_clear_obj(degreeSo)
874 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
875 85 storres
            return None
876 176 storres
        # Compute the other expansions.
877 176 storres
        # Test for insufficient precision.
878 81 storres
# End slz_get_intervals_and_polynomials
879 60 storres
880 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
881 61 storres
    """
882 151 storres
    Compute the scaling expression to map an interval that spans at most
883 166 storres
    a single binade into [1, 2) and the inverse expression as well.
884 165 storres
    If the interval spans more than one binade, result is wrong since
885 165 storres
    scaling is only based on the lower bound.
886 62 storres
    Not very sure that the transformation makes sense for negative numbers.
887 61 storres
    """
888 165 storres
    # The "one of the bounds is 0" special case. Here we consider
889 165 storres
    # the interval as the subnormals binade.
890 165 storres
    if boundsInterval.endpoints()[0] == 0 or boundsInterval.endpoints()[1] == 0:
891 165 storres
        # The upper bound is (or should be) positive.
892 165 storres
        if boundsInterval.endpoints()[0] == 0:
893 165 storres
            if boundsInterval.endpoints()[1] == 0:
894 165 storres
                return None
895 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[1])
896 165 storres
            l2     = boundsInterval.endpoints()[1].abs().log2()
897 165 storres
            # The upper bound is a power of two
898 165 storres
            if binade == l2:
899 165 storres
                scalingCoeff    = 2^(-binade)
900 165 storres
                invScalingCoeff = 2^(binade)
901 165 storres
                scalingOffset   = 1
902 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
903 165 storres
                       ((expVar - scalingOffset) * invScalingCoeff))
904 165 storres
            else:
905 165 storres
                scalingCoeff    = 2^(-binade-1)
906 165 storres
                invScalingCoeff = 2^(binade+1)
907 165 storres
                scalingOffset   = 1
908 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
909 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
910 165 storres
        # The lower bound is (or should be) negative.
911 165 storres
        if boundsInterval.endpoints()[1] == 0:
912 165 storres
            if boundsInterval.endpoints()[0] == 0:
913 165 storres
                return None
914 165 storres
            binade = slz_compute_binade(boundsInterval.endpoints()[0])
915 165 storres
            l2     = boundsInterval.endpoints()[0].abs().log2()
916 165 storres
            # The upper bound is a power of two
917 165 storres
            if binade == l2:
918 165 storres
                scalingCoeff    = -2^(-binade)
919 165 storres
                invScalingCoeff = -2^(binade)
920 165 storres
                scalingOffset   = 1
921 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
922 165 storres
                    ((expVar - scalingOffset) * invScalingCoeff))
923 165 storres
            else:
924 165 storres
                scalingCoeff    = -2^(-binade-1)
925 165 storres
                invScalingCoeff = -2^(binade+1)
926 165 storres
                scalingOffset   = 1
927 165 storres
                return((scalingCoeff * expVar + scalingOffset),\
928 165 storres
                   ((expVar - scalingOffset) * invScalingCoeff))
929 165 storres
    # General case
930 165 storres
    lbBinade = slz_compute_binade(boundsInterval.endpoints()[0])
931 165 storres
    ubBinade = slz_compute_binade(boundsInterval.endpoints()[1])
932 165 storres
    # We allow for a single exception in binade spanning is when the
933 165 storres
    # "outward bound" is a power of 2 and its binade is that of the
934 165 storres
    # "inner bound" + 1.
935 165 storres
    if boundsInterval.endpoints()[0] > 0:
936 165 storres
        ubL2 = boundsInterval.endpoints()[1].abs().log2()
937 165 storres
        if lbBinade != ubBinade:
938 165 storres
            print "Different binades."
939 165 storres
            if ubL2 != ubBinade:
940 165 storres
                print "Not a power of 2."
941 165 storres
                return None
942 165 storres
            elif abs(ubBinade - lbBinade) > 1:
943 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
944 165 storres
                return None
945 165 storres
    else:
946 165 storres
        lbL2 = boundsInterval.endpoints()[0].abs().log2()
947 165 storres
        if lbBinade != ubBinade:
948 165 storres
            print "Different binades."
949 165 storres
            if lbL2 != lbBinade:
950 165 storres
                print "Not a power of 2."
951 165 storres
                return None
952 165 storres
            elif abs(ubBinade - lbBinade) > 1:
953 165 storres
                print "Too large span:", abs(ubBinade - lbBinade)
954 165 storres
                return None
955 165 storres
    #print "Lower bound binade:", binade
956 165 storres
    if boundsInterval.endpoints()[0] > 0:
957 165 storres
        return((2^(-lbBinade) * expVar),(2^(lbBinade) * expVar))
958 165 storres
    else:
959 166 storres
        return((-(2^(-ubBinade)) * expVar),(-(2^(ubBinade)) * expVar))
960 165 storres
"""
961 165 storres
    # Code sent to attic. Should be the base for a
962 165 storres
    # "slz_interval_translate_expression" rather than scale.
963 165 storres
    # Extra control and special cases code  added in
964 165 storres
    # slz_interval_scaling_expression could (should ?) be added to
965 165 storres
    # this new function.
966 62 storres
    # The scaling offset is only used for negative numbers.
967 151 storres
    # When the absolute value of the lower bound is < 0.
968 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
969 61 storres
        if boundsInterval.endpoints()[0] >= 0:
970 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
971 62 storres
            invScalingCoeff = 1/scalingCoeff
972 80 storres
            return((scalingCoeff * expVar,
973 80 storres
                    invScalingCoeff * expVar))
974 60 storres
        else:
975 62 storres
            scalingCoeff = \
976 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
977 62 storres
            scalingOffset = -3 * scalingCoeff
978 80 storres
            return((scalingCoeff * expVar + scalingOffset,
979 80 storres
                    1/scalingCoeff * expVar + 3))
980 61 storres
    else:
981 61 storres
        if boundsInterval.endpoints()[0] >= 0:
982 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
983 61 storres
            scalingOffset = 0
984 80 storres
            return((scalingCoeff * expVar,
985 80 storres
                    1/scalingCoeff * expVar))
986 61 storres
        else:
987 62 storres
            scalingCoeff = \
988 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
989 62 storres
            scalingOffset =  -3 * scalingCoeff
990 62 storres
            #scalingOffset = 0
991 80 storres
            return((scalingCoeff * expVar + scalingOffset,
992 80 storres
                    1/scalingCoeff * expVar + 3))
993 165 storres
"""
994 151 storres
# End slz_interval_scaling_expression
995 61 storres
996 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
997 72 storres
    """
998 72 storres
    Compute the Sage version of the Taylor polynomial and it's
999 72 storres
    companion data (interval, center...)
1000 72 storres
    The input parameter is a five elements tuple:
1001 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
1002 79 storres
           real ring;
1003 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
1004 79 storres
           over a real ring;
1005 72 storres
    - [2]: the interval (as Sollya range);
1006 72 storres
    - [3]: the interval center;
1007 72 storres
    - [4]: the approximation error.
1008 72 storres
1009 72 storres
    The function return a 5 elements tuple: formed with all the
1010 72 storres
    input elements converted into their Sollya counterpart.
1011 72 storres
    """
1012 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
1013 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
1014 60 storres
    intervalSa = \
1015 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
1016 60 storres
    centerSa = \
1017 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
1018 60 storres
    errorSa = \
1019 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
1020 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
1021 83 storres
    # End slz_interval_and_polynomial_to_sage
1022 62 storres
1023 172 storres
def slz_is_htrn(argument, function, targetAccuracy, targetRF = None,
1024 172 storres
            targetPlusOnePrecRF = None, quasiExactRF = None):
1025 172 storres
    """
1026 172 storres
      Check if an element (argument) of the domain of function (function)
1027 172 storres
      yields a HTRN case (rounding to next) for the target precision
1028 172 storres
      (as impersonated by targetRF) for a given accuracy (targetAccuraty).
1029 172 storres
    """
1030 172 storres
    ## Arguments filtering. TODO: filter the first argument for consistence.
1031 172 storres
    ## If no target accuracy is given, assume it is that of the argument.
1032 172 storres
    if targetRF is None:
1033 172 storres
        targetRF = argument.parent()
1034 172 storres
    ## Ditto for the real field holding the midpoints.
1035 172 storres
    if targetPlusOnePrecRF is None:
1036 172 storres
        targetPlusOnePrecRF = RealField(targetRF.prec()+1)
1037 172 storres
    ## Create a high accuracy RealField
1038 172 storres
    if quasiExactRF is None:
1039 172 storres
        quasiExactRF = RealField(1536)
1040 177 storres
    #functionVariable              = function.variables()[0]
1041 172 storres
    exactArgument                 = quasiExactRF(argument)
1042 172 storres
    quasiExactValue               = function(exactArgument)
1043 172 storres
    roundedValue                  = targetRF(quasiExactValue)
1044 172 storres
    roundedValuePrecPlusOne       = targetPlusOnePrecRF(roundedValue)
1045 172 storres
    # Upper midpoint.
1046 172 storres
    roundedValuePrecPlusOneNext   = roundedValuePrecPlusOne.nextabove()
1047 172 storres
    # Lower midpoint.
1048 172 storres
    roundedValuePrecPlusOnePrev   = roundedValuePrecPlusOne.nextbelow()
1049 172 storres
    binade                        = slz_compute_binade(roundedValue)
1050 172 storres
    binadeCorrectedTargetAccuracy = targetAccuracy * 2^binade
1051 172 storres
    #print "Argument:", argument
1052 172 storres
    #print "f(x):", roundedValue, binade, floor(binade), ceil(binade)
1053 174 storres
    #print "Binade:", binade
1054 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1055 174 storres
    #binadeCorrectedTargetAccuracy.n(prec=100)
1056 172 storres
    #print "binadeCorrectedTargetAccuracy:", \
1057 172 storres
    #  binadeCorrectedTargetAccuracy.n(prec=100).str(base=2)
1058 172 storres
    #print "Upper midpoint:", \
1059 172 storres
    #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1060 172 storres
    #print "Rounded value :", \
1061 172 storres
    #  roundedValuePrecPlusOne.n(prec=targetPlusOnePrecRF.prec()).str(base=2), \
1062 172 storres
    #  roundedValuePrecPlusOne.ulp().n(prec=2).str(base=2)
1063 172 storres
    #print "QuasiEx value :", quasiExactValue.n(prec=250).str(base=2)
1064 172 storres
    #print "Lower midpoint:", \
1065 172 storres
    #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1066 172 storres
    ## Begining of the general case : check with the midpoint with
1067 172 storres
    #  greatest absolute value.
1068 172 storres
    if quasiExactValue > 0:
1069 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) <\
1070 172 storres
           binadeCorrectedTargetAccuracy:
1071 172 storres
            #print "Too close to the upper midpoint: ", \
1072 174 storres
            #abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1073 172 storres
            #print argument.n().str(base=16, \
1074 172 storres
            #  no_sci=False)
1075 172 storres
            #print "Lower midpoint:", \
1076 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1077 172 storres
            #print "Value         :", \
1078 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1079 172 storres
            #print "Upper midpoint:", \
1080 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1081 172 storres
            #print
1082 172 storres
            return True
1083 172 storres
    else:
1084 172 storres
        if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1085 172 storres
           binadeCorrectedTargetAccuracy:
1086 172 storres
            #print "Too close to the upper midpoint: ", \
1087 172 storres
            #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100)
1088 172 storres
            #print argument.n().str(base=16, \
1089 172 storres
            #  no_sci=False)
1090 172 storres
            #print "Lower midpoint:", \
1091 172 storres
            #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1092 172 storres
            #print "Value         :", \
1093 172 storres
            #  quasiExactValue.n(prec=200).str(base=2)
1094 172 storres
            #print "Upper midpoint:", \
1095 172 storres
            #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1096 172 storres
            #print
1097 172 storres
            return True
1098 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1099 172 storres
    ## For the midpoint of smaller absolute value,
1100 172 storres
    #  split cases with the powers of 2.
1101 172 storres
    if sno_abs_is_power_of_two(roundedValue):
1102 172 storres
        if quasiExactValue > 0:
1103 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) <\
1104 172 storres
               binadeCorrectedTargetAccuracy / 2:
1105 172 storres
                #print "Lower midpoint:", \
1106 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1107 172 storres
                #print "Value         :", \
1108 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1109 172 storres
                #print "Upper midpoint:", \
1110 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1111 172 storres
                #print
1112 172 storres
                return True
1113 172 storres
        else:
1114 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1115 172 storres
              binadeCorrectedTargetAccuracy / 2:
1116 172 storres
                #print "Lower midpoint:", \
1117 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1118 172 storres
                #print "Value         :",
1119 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1120 172 storres
                #print "Upper midpoint:",
1121 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1122 172 storres
                #print
1123 172 storres
                return True
1124 172 storres
#2345678901234567890123456789012345678901234567890123456789012345678901234567890
1125 172 storres
    else: ## Not a power of 2, regular comparison with the midpoint of
1126 172 storres
          #  smaller absolute value.
1127 172 storres
        if quasiExactValue > 0:
1128 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue) < \
1129 172 storres
              binadeCorrectedTargetAccuracy:
1130 172 storres
                #print "Lower midpoint:", \
1131 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1132 172 storres
                #print "Value         :", \
1133 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1134 172 storres
                #print "Upper midpoint:", \
1135 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1136 172 storres
                #print
1137 172 storres
                return True
1138 172 storres
        else: # quasiExactValue <= 0
1139 172 storres
            if abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue) < \
1140 172 storres
              binadeCorrectedTargetAccuracy:
1141 172 storres
                #print "Lower midpoint:", \
1142 172 storres
                #  roundedValuePrecPlusOnePrev.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1143 172 storres
                #print "Value         :", \
1144 172 storres
                #  quasiExactValue.n(prec=200).str(base=2)
1145 172 storres
                #print "Upper midpoint:", \
1146 172 storres
                #  roundedValuePrecPlusOneNext.n(prec=targetPlusOnePrecRF.prec()).str(base=2)
1147 172 storres
                #print
1148 172 storres
                return True
1149 172 storres
    #print "distance to the upper midpoint:", \
1150 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOneNext) - quasiExactValue).n(prec=100).str(base=2)
1151 172 storres
    #print "distance to the lower midpoint:", \
1152 172 storres
    #  abs(quasiExactRF(roundedValuePrecPlusOnePrev) - quasiExactValue).n(prec=100).str(base=2)
1153 172 storres
    return False
1154 172 storres
# End slz_is_htrn
1155 172 storres
1156 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
1157 80 storres
                                                precision,
1158 80 storres
                                                targetHardnessToRound,
1159 80 storres
                                                variable1,
1160 80 storres
                                                variable2):
1161 80 storres
    """
1162 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
1163 90 storres
     with the Coppersmith method.
1164 80 storres
    A the same time it computes :
1165 80 storres
    - 2^K (N);
1166 90 storres
    - 2^k (bound on the second variable)
1167 80 storres
    - lcm
1168 90 storres
1169 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
1170 90 storres
                         variables.
1171 90 storres
    :param precision: the precision of the floating-point coefficients.
1172 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
1173 90 storres
    :param variable1: the first variable of the polynomial (an expression).
1174 90 storres
    :param variable2: the second variable of the polynomial (an expression).
1175 90 storres
1176 90 storres
    :returns: a 4 elements tuple:
1177 90 storres
                - the polynomial;
1178 91 storres
                - the modulus (N);
1179 91 storres
                - the t bound;
1180 90 storres
                - the lcm used to compute the integral coefficients and the
1181 90 storres
                  module.
1182 80 storres
    """
1183 80 storres
    # Create a new integer polynomial ring.
1184 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
1185 80 storres
    # Coefficients are issued in the increasing power order.
1186 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
1187 91 storres
    # Print the reversed list for debugging.
1188 170 storres
    print
1189 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
1190 94 storres
    # Build the list of number we compute the lcm of.
1191 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
1192 170 storres
    print "Coefficient denominators:", coefficientDenominators
1193 80 storres
    coefficientDenominators.append(2^precision)
1194 170 storres
    coefficientDenominators.append(2^(targetHardnessToRound))
1195 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
1196 80 storres
    # Compute the expression corresponding to the new polynomial
1197 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
1198 91 storres
    #print coefficientNumerators
1199 80 storres
    polynomialExpression = 0
1200 80 storres
    power = 0
1201 170 storres
    # Iterate over two lists at the same time, stop when the shorter
1202 170 storres
    # (is this case coefficientsNumerators) is
1203 170 storres
    # exhausted. Both lists are ordered in the order of increasing powers
1204 170 storres
    # of variable1.
1205 80 storres
    for numerator, denominator in \
1206 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
1207 80 storres
        multiplicator = leastCommonMultiple / denominator
1208 80 storres
        newCoefficient = numerator * multiplicator
1209 80 storres
        polynomialExpression += newCoefficient * variable1^power
1210 80 storres
        power +=1
1211 80 storres
    polynomialExpression += - variable2
1212 80 storres
    return (IP(polynomialExpression),
1213 170 storres
            leastCommonMultiple / 2^precision, # 2^K aka N.
1214 170 storres
            #leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
1215 170 storres
            leastCommonMultiple / 2^(targetHardnessToRound), # tBound
1216 91 storres
            leastCommonMultiple) # If we want to make test computations.
1217 80 storres
1218 170 storres
# End slz_rat_poly_of_int_to_poly_for_coppersmith
1219 79 storres
1220 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
1221 79 storres
                                          precision):
1222 79 storres
    """
1223 79 storres
    Makes a variable substitution into the input polynomial so that the output
1224 79 storres
    polynomial can take integer arguments.
1225 79 storres
    All variables of the input polynomial "have precision p". That is to say
1226 103 storres
    that they are rationals with denominator == 2^(precision - 1):
1227 103 storres
    x = y/2^(precision - 1).
1228 79 storres
    We "incorporate" these denominators into the coefficients with,
1229 79 storres
    respectively, the "right" power.
1230 79 storres
    """
1231 79 storres
    polynomialField = ratPolyOfRat.parent()
1232 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
1233 91 storres
    #print "The polynomial field is:", polynomialField
1234 79 storres
    return \
1235 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1236 79 storres
                                   polynomialVariable/2^(precision-1)}))
1237 79 storres
1238 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1239 79 storres
1240 177 storres
def slz_reduce_and_test_base(matrixToReduce,
1241 177 storres
                             nAtAlpha,
1242 177 storres
                             monomialsCountSqrt):
1243 177 storres
    """
1244 177 storres
    Reduces the basis, tests the Coppersmith condition and returns
1245 177 storres
    a list of rows that comply with the condition.
1246 177 storres
    """
1247 177 storres
    ccComplientRowsList = []
1248 177 storres
    reducedMatrix = matrixToReduce.LLL(None)
1249 177 storres
    if not reducedMatrix.is_LLL_reduced():
1250 177 storres
        raise Exception("reducedMatrix is not actually reduced. Aborting!")
1251 177 storres
    else:
1252 177 storres
        print "reducedMatrix is actually reduced."
1253 177 storres
    print "N^alpha:", nAtAlpha.n()
1254 177 storres
    rowIndex = 0
1255 177 storres
    for row in reducedMatrix.rows():
1256 177 storres
        l2Norm = row.norm(2)
1257 177 storres
        print "L_2 norm for vector # ", rowIndex, "= ", RR(l2Norm), "*", \
1258 177 storres
                monomialsCountSqrt.n(), ". Is vector OK?",
1259 177 storres
        if (l2Norm * monomialsCountSqrt < nAtAlpha):
1260 177 storres
            ccComplientRowsList.append(row)
1261 177 storres
            print "True"
1262 177 storres
        else:
1263 177 storres
            print "False"
1264 177 storres
    # End for
1265 177 storres
    return ccComplientRowsList
1266 177 storres
# End slz_reduce_and_test_base
1267 115 storres
1268 177 storres
def slz_resultant_tuple(poly1, poly2, elimVar):
1269 177 storres
    polynomialRing0 = poly1.parent()
1270 177 storres
    resultantInElimVar = poly1.resultant(poly2,polynomialRing0(elimVar))
1271 177 storres
    if resultantInElimVar.is_zero():
1272 177 storres
        return ()
1273 177 storres
    else:
1274 177 storres
        return (poly1, poly2, resultantInElimVar)
1275 177 storres
# End slz_resultant_tuple.
1276 177 storres
#
1277 87 storres
print "\t...sageSLZ loaded"