Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (43,61 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 115 storres
def slz_check_htr_value(function, htrValue, lowerBound, upperBound, precision, \
14 115 storres
                        degree, targetHardnessToRound, alpha):
15 115 storres
    """
16 115 storres
    Check an Hard-to-round value.
17 124 storres
    TODO::
18 124 storres
    Full rewriting: this is hardly a draft.
19 115 storres
    """
20 115 storres
    polyApproxPrec = targetHardnessToRound + 1
21 115 storres
    polyTargetHardnessToRound = targetHardnessToRound + 1
22 115 storres
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
23 115 storres
    RRR = htrValue.parent()
24 115 storres
    #
25 115 storres
    ## Compute the scaled function.
26 115 storres
    fff = slz_compute_scaled_function(f, lowerBound, upperBound, precision)[0]
27 115 storres
    print "Scaled function:", fff
28 115 storres
    #
29 115 storres
    ## Compute the scaling.
30 115 storres
    boundsIntervalRifSa = RealIntervalField(precision)
31 115 storres
    domainBoundsInterval = boundsIntervalRifSa(lowerBound, upperBound)
32 115 storres
    scalingExpressions = \
33 115 storres
        slz_interval_scaling_expression(domainBoundsInterval, i)
34 115 storres
    #
35 115 storres
    ## Get the polynomials, bounds, etc. for all the interval.
36 115 storres
    resultListOfTuplesOfSo = \
37 115 storres
        slz_get_intervals_and_polynomials(f, degree, lowerBound, upperBound, \
38 115 storres
                                          precision, internalSollyaPrec,\
39 115 storres
                                          2^-(polyApproxPrec))
40 115 storres
    #
41 115 storres
    ## We only want one interval.
42 115 storres
    if len(resultListOfTuplesOfSo) > 1:
43 115 storres
        print "Too many intervals! Aborting!"
44 115 storres
        exit
45 115 storres
    #
46 115 storres
    ## Get the first tuple of Sollya objects as Sage objects.
47 115 storres
    firstTupleSa = \
48 115 storres
        slz_interval_and_polynomial_to_sage(resultListOfTuplesOfSo[0])
49 115 storres
    pobyso_set_canonical_on()
50 115 storres
    #
51 115 storres
    print "Floatting point polynomial:", firstTupleSa[0]
52 115 storres
    print "with coefficients precision:", firstTupleSa[0].base_ring().prec()
53 115 storres
    #
54 115 storres
    ## From a polynomial over a real ring, create a polynomial over the
55 115 storres
    #  rationals ring.
56 115 storres
    rationalPolynomial = \
57 115 storres
        slz_float_poly_of_float_to_rat_poly_of_rat(firstTupleSa[0])
58 115 storres
    print "Rational polynomial:", rationalPolynomial
59 115 storres
    #
60 115 storres
    ## Create a polynomial over the rationals that will take integer
61 115 storres
    # variables instead of rational.
62 115 storres
    rationalPolynomialOfIntegers = \
63 115 storres
        slz_rat_poly_of_rat_to_rat_poly_of_int(rationalPolynomial, precision)
64 115 storres
    print "Type:", type(rationalPolynomialOfIntegers)
65 115 storres
    print "Rational polynomial of integers:", rationalPolynomialOfIntegers
66 115 storres
    #
67 115 storres
    ## Check the rational polynomial of integers variables.
68 115 storres
    # (check against the scaled function).
69 115 storres
    toIntegerFactor = 2^(precision-1)
70 115 storres
    intervalCenterAsIntegerSa = int(firstTupleSa[3] * toIntegerFactor)
71 115 storres
    print "Interval center as integer:", intervalCenterAsIntegerSa
72 115 storres
    lowerBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[0] * \
73 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
74 115 storres
    upperBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[1] * \
75 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
76 115 storres
    print "Lower bound as integer:", lowerBoundAsIntegerSa
77 115 storres
    print "Upper bound as integer:", upperBoundAsIntegerSa
78 115 storres
    print "Image of the lower bound by the scaled function", \
79 115 storres
            fff(firstTupleSa[2].endpoints()[0])
80 115 storres
    print "Image of the lower bound by the approximation polynomial of ints:", \
81 115 storres
            RRR(rationalPolynomialOfIntegers(lowerBoundAsIntegerSa))
82 115 storres
    print "Image of the center by the scaled function", fff(firstTupleSa[3])
83 115 storres
    print "Image of the center by the approximation polynomial of ints:", \
84 115 storres
            RRR(rationalPolynomialOfIntegers(0))
85 115 storres
    print "Image of the upper bound by the scaled function", \
86 115 storres
            fff(firstTupleSa[2].endpoints()[1])
87 115 storres
    print "Image of the upper bound by the approximation polynomial of ints:", \
88 115 storres
            RRR(rationalPolynomialOfIntegers(upperBoundAsIntegerSa))
89 115 storres
90 115 storres
# End slz_check_htr_value.
91 122 storres
92 115 storres
#
93 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
94 119 storres
    """
95 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
96 121 storres
97 121 storres
    NOTE::
98 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
99 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
100 121 storres
        with interval [-infinity, -2^(emax+1)].
101 121 storres
102 119 storres
    """
103 121 storres
    # Check the parameters.
104 121 storres
    # RealNumbers only.
105 124 storres
    try:
106 124 storres
        classTree = [number.__class__] + number.mro()
107 124 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
108 124 storres
            return None
109 124 storres
    except AttributeError:
110 121 storres
        return None
111 121 storres
    # Non zero negative integers only for emin.
112 121 storres
    if emin >= 0 or int(emin) != emin:
113 121 storres
        return None
114 121 storres
    # Non zero positive integers only for emax.
115 121 storres
    if emax <= 0 or int(emax) != emax:
116 121 storres
        return None
117 121 storres
    precision = number.precision()
118 121 storres
    RF  = RealField(precision)
119 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
120 121 storres
    # when computing number.log2().
121 121 storres
    RRF = RealField(max(2048, 2 * precision))
122 121 storres
    # number = 0 special case, the binade bounds are
123 121 storres
    # [0, 2^emin - 2^(emin-precision)]
124 119 storres
    if number == 0:
125 119 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
126 121 storres
    # Begin general case
127 119 storres
    l2 = RRF(number).abs().log2()
128 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
129 121 storres
    if l2 >= emax + 1:
130 121 storres
        if number > 0:
131 121 storres
            return (RF(2^(emax+1)), RRR(+infinity) )
132 121 storres
        else:
133 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
134 119 storres
    offset = int(l2)
135 121 storres
    # number.abs() >= 1.
136 119 storres
    if l2 >= 0:
137 119 storres
        if number >= 0:
138 119 storres
            lb = RF(2^offset)
139 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
140 119 storres
        else: #number < 0
141 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
142 119 storres
            ub = -RF(2^offset)
143 121 storres
    else: # log2 < 0, number.abs() < 1.
144 119 storres
        if l2 < emin: # Denormal
145 121 storres
           # print "Denormal:", l2
146 119 storres
            if number >= 0:
147 119 storres
                lb = RF(0)
148 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
149 119 storres
            else: # number <= 0
150 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
151 119 storres
                ub = RF(0)
152 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
153 119 storres
            if number >= 0:
154 121 storres
                if int(l2) == l2:
155 121 storres
                    lb = RF(2^(offset))
156 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
157 121 storres
                else:
158 121 storres
                    lb = RF(2^(offset-1))
159 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
160 119 storres
            else: # number < 0
161 121 storres
                if int(l2) == l2: # Binade limit.
162 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
163 121 storres
                    ub = -RF(2^(offset))
164 121 storres
                else:
165 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
166 121 storres
                    ub = -RF(2^(offset-1))
167 121 storres
        else: # l2== emin, number == +/-2^emin
168 119 storres
            if number >= 0:
169 119 storres
                lb = RF(2^(offset))
170 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
171 119 storres
            else: # number < 0
172 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
173 119 storres
                ub = -RF(2^(offset))
174 119 storres
    return (lb, ub)
175 119 storres
# End slz_compute_binade_bounds
176 119 storres
#
177 123 storres
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
178 123 storres
                                                 alpha,
179 123 storres
                                                 N,
180 123 storres
                                                 iBound,
181 123 storres
                                                 tBound):
182 123 storres
    """
183 123 storres
    For a given set of arguments (see below), compute a list
184 123 storres
    of "reduced polynomials" that could be used to compute roots
185 123 storres
    of the inputPolynomial.
186 124 storres
    INPUT:
187 124 storres
188 124 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
189 124 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
190 124 storres
    - "N" -- the modulus;
191 124 storres
    - "iBound" -- the bound on the first variable;
192 124 storres
    - "tBound" -- the bound on the second variable.
193 124 storres
194 124 storres
    OUTPUT:
195 124 storres
196 124 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
197 124 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
198 124 storres
    reduced base that comply with the Coppersmith condition.
199 124 storres
200 124 storres
    TODO::
201 124 storres
    Full rewrite, this is barely a draft.
202 123 storres
    """
203 123 storres
    # Arguments check.
204 123 storres
    if iBound == 0 or tBound == 0:
205 123 storres
        return ()
206 123 storres
    # End arguments check.
207 123 storres
    nAtAlpha = N^alpha
208 123 storres
    ## Building polynomials for matrix.
209 123 storres
    polyRing   = inputPolynomial.parent()
210 123 storres
    # Whatever the 2 variables are actually called, we call them
211 123 storres
    # 'i' and 't' in all the variable names.
212 123 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
213 123 storres
    #print polyVars[0], type(polyVars[0])
214 123 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
215 123 storres
                                              tVariable:tVariable * tBound})
216 123 storres
    polynomialsList = \
217 123 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
218 123 storres
                                             alpha,
219 123 storres
                                             N,
220 123 storres
                                             iBound,
221 123 storres
                                             tBound,
222 123 storres
                                             0)
223 123 storres
    #print "Polynomials list:", polynomialsList
224 123 storres
    ## Building the proto matrix.
225 123 storres
    knownMonomials = []
226 123 storres
    protoMatrix    = []
227 123 storres
    for poly in polynomialsList:
228 123 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
229 123 storres
                                                knownMonomials,
230 123 storres
                                                protoMatrix,
231 123 storres
                                                0)
232 123 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
233 123 storres
    #print matrixToReduce
234 123 storres
    ## Reduction and checking.
235 123 storres
    reducedMatrix = matrixToReduce.LLL(fp='fp')
236 123 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
237 123 storres
    if not isLLLReduced:
238 123 storres
        return ()
239 123 storres
    monomialsCount     = len(knownMonomials)
240 123 storres
    monomialsCountSqrt = sqrt(monomialsCount)
241 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
242 123 storres
    #print reducedMatrix
243 123 storres
    ## Check the Coppersmith condition for each row and build the reduced
244 123 storres
    #  polynomials.
245 123 storres
    ccReducedPolynomialsList = []
246 123 storres
    for row in reducedMatrix.rows():
247 123 storres
        l2Norm = row.norm(2)
248 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
249 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
250 123 storres
            print l2Norm.n()
251 123 storres
            ccReducedPolynomial = \
252 123 storres
                slz_compute_reduced_polynomial(row,
253 123 storres
                                               knownMonomials,
254 123 storres
                                               iVariable,
255 123 storres
                                               iBound,
256 123 storres
                                               tVariable,
257 123 storres
                                               tBound)
258 123 storres
            if not ccReducedPolynomial is None:
259 123 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
260 123 storres
        else:
261 123 storres
            print l2Norm.n() , ">", nAtAlpha
262 123 storres
            pass
263 123 storres
    if len(ccReducedPolynomialsList) < 2:
264 123 storres
        print "***Less than 2 Coppersmith condition compliant vectors.***"
265 123 storres
        return ()
266 123 storres
    return ccReducedPolynomialsList
267 123 storres
# End slz_compute_coppersmith_reduced_polynomials
268 123 storres
269 122 storres
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
270 122 storres
                                                 alpha,
271 122 storres
                                                 N,
272 122 storres
                                                 iBound,
273 122 storres
                                                 tBound):
274 122 storres
    """
275 123 storres
    For a given set of arguments (see below), compute the polynomial modular
276 122 storres
    roots, if any.
277 124 storres
278 122 storres
    """
279 123 storres
    # Arguments check.
280 123 storres
    if iBound == 0 or tBound == 0:
281 123 storres
        return set()
282 123 storres
    # End arguments check.
283 122 storres
    nAtAlpha = N^alpha
284 122 storres
    ## Building polynomials for matrix.
285 122 storres
    polyRing   = inputPolynomial.parent()
286 122 storres
    # Whatever the 2 variables are actually called, we call them
287 122 storres
    # 'i' and 't' in all the variable names.
288 122 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
289 122 storres
    #print polyVars[0], type(polyVars[0])
290 122 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
291 122 storres
                                              tVariable:tVariable * tBound})
292 122 storres
    polynomialsList = \
293 122 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
294 122 storres
                                             alpha,
295 122 storres
                                             N,
296 122 storres
                                             iBound,
297 122 storres
                                             tBound,
298 123 storres
                                             0)
299 123 storres
    #print "Polynomials list:", polynomialsList
300 122 storres
    ## Building the proto matrix.
301 122 storres
    knownMonomials = []
302 122 storres
    protoMatrix    = []
303 122 storres
    for poly in polynomialsList:
304 122 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
305 122 storres
                                                knownMonomials,
306 122 storres
                                                protoMatrix,
307 122 storres
                                                0)
308 122 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
309 122 storres
    #print matrixToReduce
310 122 storres
    ## Reduction and checking.
311 122 storres
    reducedMatrix = matrixToReduce.LLL(fp='fp')
312 122 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
313 122 storres
    if not isLLLReduced:
314 123 storres
        return set()
315 122 storres
    monomialsCount     = len(knownMonomials)
316 122 storres
    monomialsCountSqrt = sqrt(monomialsCount)
317 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
318 123 storres
    #print reducedMatrix
319 122 storres
    ## Check the Coppersmith condition for each row and build the reduced
320 122 storres
    #  polynomials.
321 122 storres
    ccReducedPolynomialsList = []
322 122 storres
    for row in reducedMatrix.rows():
323 122 storres
        l2Norm = row.norm(2)
324 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
325 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
326 123 storres
            #print l2Norm.n()
327 122 storres
            ccReducedPolynomial = \
328 122 storres
                slz_compute_reduced_polynomial(row,
329 122 storres
                                               knownMonomials,
330 122 storres
                                               iVariable,
331 122 storres
                                               iBound,
332 122 storres
                                               tVariable,
333 122 storres
                                               tBound)
334 122 storres
            if not ccReducedPolynomial is None:
335 122 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
336 123 storres
        else:
337 123 storres
            #print l2Norm.n() , ">", nAtAlpha
338 123 storres
            pass
339 122 storres
    if len(ccReducedPolynomialsList) < 2:
340 122 storres
        print "Less than 2 Coppersmith condition compliant vectors."
341 123 storres
        return set()
342 123 storres
    #print ccReducedPolynomialsList
343 122 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
344 122 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
345 122 storres
    # Try to mix and match all the polynomial pairs built from the
346 122 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
347 122 storres
    resultantsInITuplesList = []
348 122 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
349 122 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
350 122 storres
                                     len(ccReducedPolynomialsList)):
351 122 storres
            # Compute the resultant in resultants in the
352 122 storres
            # first variable (is it the optimal choice?).
353 122 storres
            resultantInI = \
354 122 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
355 122 storres
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
356 122 storres
            #print "Resultant", resultantInI
357 122 storres
            # Test algebraic independence.
358 122 storres
            if not resultantInI.is_zero():
359 122 storres
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
360 122 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
361 122 storres
                                                 resultantInI))
362 122 storres
    # If no non zero resultant was found: we can't get no algebraically
363 122 storres
    # independent polynomials pair. Give up!
364 122 storres
    if len(resultantsInITuplesList) == 0:
365 123 storres
        return set()
366 123 storres
    #print resultantsInITuplesList
367 122 storres
    # Compute the roots.
368 122 storres
    Zi = ZZ[str(iVariable)]
369 122 storres
    Zt = ZZ[str(tVariable)]
370 122 storres
    polynomialRootsSet = set()
371 122 storres
    # First, solve in the second variable since resultants are in the first
372 122 storres
    # variable.
373 122 storres
    for resultantInITuple in resultantsInITuplesList:
374 122 storres
        tRootsList = Zt(resultantInITuple[2]).roots()
375 122 storres
        # For each tRoot, compute the corresponding iRoots and check
376 123 storres
        # them in the input polynomial.
377 122 storres
        for tRoot in tRootsList:
378 123 storres
            #print "tRoot:", tRoot
379 122 storres
            # Roots returned by root() are (value, multiplicity) tuples.
380 122 storres
            iRootsList = \
381 122 storres
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
382 123 storres
            print iRootsList
383 122 storres
            # The iRootsList can be empty, hence the test.
384 122 storres
            if len(iRootsList) != 0:
385 122 storres
                for iRoot in iRootsList:
386 122 storres
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
387 122 storres
                    # polyEvalModN must be an integer.
388 122 storres
                    if polyEvalModN == int(polyEvalModN):
389 122 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
390 122 storres
    return polynomialRootsSet
391 122 storres
# End slz_compute_integer_polynomial_modular_roots.
392 122 storres
#
393 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
394 61 storres
                                        upperBoundSa, approxPrecSa,
395 61 storres
                                        sollyaPrecSa=None):
396 61 storres
    """
397 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
398 61 storres
    a polynomial that approximates the function on a an interval starting
399 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
400 61 storres
    approximates with the expected precision.
401 61 storres
    The interval upper bound is lowered until the expected approximation
402 61 storres
    precision is reached.
403 61 storres
    The polynomial, the bounds, the center of the interval and the error
404 61 storres
    are returned.
405 124 storres
    OUTPU:
406 124 storres
    A tuple made of 4 Sollya objects:
407 124 storres
    - a polynomial;
408 124 storres
    - an range (an interval, not in the sense of number given as an interval);
409 124 storres
    - the center of the interval;
410 124 storres
    - the maximum error in the approximation of the input functionSo by the
411 124 storres
      output polynomial ; this error <= approxPrecSaS.
412 124 storres
413 61 storres
    """
414 61 storres
    RRR = lowerBoundSa.parent()
415 61 storres
    intervalShrinkConstFactorSa = RRR('0.5')
416 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
417 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
418 61 storres
    currentUpperBoundSa = upperBoundSa
419 61 storres
    currentLowerBoundSa = lowerBoundSa
420 61 storres
    # What we want here is the polynomial without the variable change,
421 61 storres
    # since our actual variable will be x-intervalCenter defined over the
422 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
423 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
424 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
425 61 storres
                                                    currentRangeSo,
426 61 storres
                                                    absoluteErrorTypeSo)
427 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
428 61 storres
    while maxErrorSa > approxPrecSa:
429 101 storres
        #print "++Approximation error:", maxErrorSa
430 81 storres
        sollya_lib_clear_obj(polySo)
431 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
432 120 storres
        sollya_lib_clear_obj(maxErrorSo)
433 101 storres
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
434 81 storres
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
435 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
436 61 storres
        #print "Error ratio: ", errorRatioSa
437 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
438 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
439 81 storres
            #print "Fixed"
440 61 storres
        else:
441 81 storres
            actualShrinkFactorSa = shrinkFactorSa
442 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
443 81 storres
            #print shrinkFactorSa, maxErrorSa
444 101 storres
        #print "Shrink factor", actualShrinkFactorSa
445 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
446 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
447 81 storres
                                   actualShrinkFactorSa
448 71 storres
        #print "Current upper bound:", currentUpperBoundSa
449 61 storres
        sollya_lib_clear_obj(currentRangeSo)
450 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
451 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
452 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
453 86 storres
            print "Can't find an interval."
454 86 storres
            print "Use either or both a higher polynomial degree or a higher",
455 86 storres
            print "internal precision."
456 86 storres
            print "Aborting!"
457 86 storres
            return (None, None, None, None)
458 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
459 61 storres
                                                      currentUpperBoundSa)
460 86 storres
        # print "New interval:",
461 86 storres
        # pobyso_autoprint(currentRangeSo)
462 120 storres
        #print "Second Taylor expansion call."
463 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
464 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
465 61 storres
                                                        currentRangeSo,
466 61 storres
                                                        absoluteErrorTypeSo)
467 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
468 85 storres
        #print "Max errorSo:",
469 85 storres
        #pobyso_autoprint(maxErrorSo)
470 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
471 85 storres
        #print "Max errorSa:", maxErrorSa
472 85 storres
        #print "Sollya prec:",
473 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
474 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
475 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
476 81 storres
# End slz_compute_polynomial_and_interval
477 61 storres
478 122 storres
def slz_compute_reduced_polynomial(matrixRow,
479 98 storres
                                    knownMonomials,
480 106 storres
                                    var1,
481 98 storres
                                    var1Bound,
482 106 storres
                                    var2,
483 99 storres
                                    var2Bound):
484 98 storres
    """
485 122 storres
    Compute a polynomial from a reduced matrix row.
486 122 storres
    This function was introduced in order to avoid the computation of the
487 122 storres
    polynomials (even those built from rows that do no verify the Coppersmith
488 122 storres
    condition.
489 122 storres
    """
490 122 storres
    ## Check arguments.
491 122 storres
    if len(knownMonomials) == 0:
492 122 storres
        return None
493 122 storres
    # varNounds can be zero since 0^0 returns 1.
494 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
495 122 storres
        return None
496 122 storres
    ## Initialisations.
497 122 storres
    polynomialRing = knownMonomials[0].parent()
498 122 storres
    currentPolynomial = polynomialRing(0)
499 123 storres
    # TODO: use zip instead of indices.
500 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
501 122 storres
        currentCoefficient = matrixRow[colIndex]
502 122 storres
        if currentCoefficient != 0:
503 122 storres
            #print "Current coefficient:", currentCoefficient
504 122 storres
            currentMonomial = knownMonomials[colIndex]
505 122 storres
            #print "Monomial as multivariate polynomial:", \
506 122 storres
            #currentMonomial, type(currentMonomial)
507 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
508 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
509 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
510 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
511 122 storres
            if degreeInVar1 > 0:
512 122 storres
                currentCoefficient = \
513 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
514 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
515 122 storres
                #print "Current coefficient(1)", currentCoefficient
516 122 storres
            if degreeInVar2 > 0:
517 122 storres
                currentCoefficient = \
518 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
519 122 storres
                #print "Current coefficient(2)", currentCoefficient
520 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
521 122 storres
            #                                    currentMonomial)
522 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
523 122 storres
            #print "Current polynomial:", currentPolynomial
524 122 storres
        # End if
525 122 storres
    # End for colIndex.
526 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
527 122 storres
    return(currentPolynomial)
528 122 storres
# End slz_compute_reduced_polynomial
529 122 storres
#
530 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
531 122 storres
                                        knownMonomials,
532 122 storres
                                        var1,
533 122 storres
                                        var1Bound,
534 122 storres
                                        var2,
535 122 storres
                                        var2Bound):
536 122 storres
    """
537 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
538 122 storres
    """
539 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
540 122 storres
                                                knownMonomials,
541 122 storres
                                                var1,
542 122 storres
                                                var1Bound,
543 122 storres
                                                var2,
544 122 storres
                                                var2Bound)
545 122 storres
    )
546 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
547 122 storres
                                        knownMonomials,
548 122 storres
                                        var1,
549 122 storres
                                        var1Bound,
550 122 storres
                                        var2,
551 122 storres
                                        var2Bound):
552 122 storres
    """
553 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
554 98 storres
    from the bounds of each variable, compute the corresponding polynomials
555 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
556 99 storres
557 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
558 103 storres
    They set the polynomial type of the output polynomials list.
559 98 storres
    """
560 99 storres
561 98 storres
    # TODO: check input arguments.
562 98 storres
    reducedPolynomials = []
563 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
564 98 storres
    for matrixRow in reducedMatrix.rows():
565 102 storres
        currentPolynomial = 0
566 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
567 98 storres
            currentCoefficient = matrixRow[colIndex]
568 106 storres
            if currentCoefficient != 0:
569 106 storres
                #print "Current coefficient:", currentCoefficient
570 106 storres
                currentMonomial = knownMonomials[colIndex]
571 106 storres
                parentRing = currentMonomial.parent()
572 106 storres
                #print "Monomial as multivariate polynomial:", \
573 106 storres
                #currentMonomial, type(currentMonomial)
574 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
575 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
576 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
577 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
578 106 storres
                if degreeInVar1 > 0:
579 106 storres
                    currentCoefficient = \
580 106 storres
                        currentCoefficient / var1Bound^degreeInVar1
581 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
582 106 storres
                    #print "Current coefficient(1)", currentCoefficient
583 106 storres
                if degreeInVar2 > 0:
584 106 storres
                    currentCoefficient = \
585 106 storres
                        currentCoefficient / var2Bound^degreeInVar2
586 106 storres
                    #print "Current coefficient(2)", currentCoefficient
587 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
588 106 storres
                #                                    currentMonomial)
589 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
590 106 storres
                #print "Current polynomial:", currentPolynomial
591 106 storres
            # End if
592 106 storres
        # End for colIndex.
593 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
594 99 storres
        reducedPolynomials.append(currentPolynomial)
595 98 storres
    return reducedPolynomials
596 99 storres
# End slz_compute_reduced_polynomials.
597 98 storres
598 114 storres
def slz_compute_scaled_function(functionSa,
599 114 storres
                                lowerBoundSa,
600 114 storres
                                upperBoundSa,
601 114 storres
                                floatingPointPrecSa):
602 72 storres
    """
603 72 storres
    From a function, compute the scaled function whose domain
604 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
605 72 storres
    Return a tuple:
606 72 storres
    [0]: the scaled function
607 72 storres
    [1]: the scaled domain lower bound
608 72 storres
    [2]: the scaled domain upper bound
609 72 storres
    [3]: the scaled image lower bound
610 72 storres
    [4]: the scaled image upper bound
611 72 storres
    """
612 80 storres
    x = functionSa.variables()[0]
613 80 storres
    # Reassert f as a function (an not a mere expression).
614 80 storres
615 72 storres
    # Scalling the domain -> [1,2[.
616 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
617 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
618 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
619 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
620 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
621 72 storres
    print "f: ", f
622 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
623 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
624 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
625 80 storres
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
626 80 storres
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
627 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
628 72 storres
    #
629 72 storres
    # Scalling the image -> [1,2[.
630 72 storres
    flbSa = f(lowerBoundSa).n()
631 72 storres
    fubSa = f(upperBoundSa).n()
632 72 storres
    if flbSa <= fubSa: # Increasing
633 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
634 72 storres
    else: # Decreasing
635 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
636 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
637 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
638 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
639 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
640 72 storres
    iis = invImageScalingExpressionSa.function(x)
641 72 storres
    fff = iis.subs({x:ff})
642 72 storres
    print "fff:", fff,
643 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
644 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
645 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
646 72 storres
647 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
648 79 storres
    # Create a polynomial over the rationals.
649 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
650 79 storres
    return(polynomialRing(polyOfFloat))
651 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
652 81 storres
653 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
654 63 storres
                                      lowerBoundSa,
655 60 storres
                                      upperBoundSa, floatingPointPrecSa,
656 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
657 60 storres
    """
658 60 storres
    Under the assumption that:
659 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
660 60 storres
    - lowerBound and upperBound belong to the same binade.
661 60 storres
    from a:
662 60 storres
    - function;
663 60 storres
    - a degree
664 60 storres
    - a pair of bounds;
665 60 storres
    - the floating-point precision we work on;
666 60 storres
    - the internal Sollya precision;
667 64 storres
    - the requested approximation error
668 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
669 61 storres
    It return a list of tuples, each made of:
670 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
671 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
672 61 storres
    - the approximation interval;
673 72 storres
    - the center, x0, of the interval;
674 61 storres
    - the corresponding approximation error.
675 100 storres
    TODO: fix endless looping for some parameters sets.
676 60 storres
    """
677 120 storres
    resultArray = []
678 101 storres
    # Set Sollya to the necessary internal precision.
679 120 storres
    precChangedSa = False
680 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
681 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
682 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
683 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
684 120 storres
        precChangedSa = True
685 101 storres
    #
686 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
687 101 storres
    # Scaled function: [1=,2] -> [1,2].
688 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
689 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
690 115 storres
                slz_compute_scaled_function(functionSa,                       \
691 115 storres
                                            lowerBoundSa,                     \
692 115 storres
                                            upperBoundSa,                     \
693 80 storres
                                            floatingPointPrecSa)
694 60 storres
    #
695 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
696 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
697 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
698 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
699 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
700 61 storres
                                                  scaledUpperBoundSa)
701 61 storres
    # Compute the first Taylor expansion.
702 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
703 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
704 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
705 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
706 86 storres
    if polySo is None:
707 101 storres
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
708 120 storres
        if precChangedSa:
709 120 storres
            pobyso_set_prec_so_so(currentSollyaPrecSo)
710 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
711 115 storres
        sollya_lib_clear_obj(functionSo)
712 115 storres
        sollya_lib_clear_obj(degreeSo)
713 115 storres
        sollya_lib_clear_obj(scaledBoundsSo)
714 86 storres
        return None
715 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
716 60 storres
                                              upperBoundSa.parent().precision()))
717 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
718 101 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
719 101 storres
    #print "First approximation error:", errorSa
720 101 storres
    # If the error and interval are OK a the first try, just return.
721 101 storres
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
722 101 storres
        # Change variable stuff in Sollya x -> x0-x.
723 101 storres
        changeVarExpressionSo = sollya_lib_build_function_sub( \
724 101 storres
                              sollya_lib_build_function_free_variable(), \
725 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
726 101 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
727 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
728 101 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
729 101 storres
                            intervalCenterSo, maxErrorSo))
730 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
731 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
732 115 storres
        sollya_lib_clear_obj(currentSollyaPrecSo)
733 101 storres
        sollya_lib_clear_obj(functionSo)
734 101 storres
        sollya_lib_clear_obj(degreeSo)
735 101 storres
        sollya_lib_clear_obj(scaledBoundsSo)
736 101 storres
        #print "Approximation error:", errorSa
737 101 storres
        return resultArray
738 120 storres
    # The returned interval upper bound does not reach the requested upper
739 120 storres
    # upper bound: compute the next upper bound.
740 101 storres
    # The following ratio is always >= 1
741 81 storres
    currentErrorRatio = approxPrecSa / errorSa
742 101 storres
    # Starting point for the next upper bound.
743 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
744 101 storres
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
745 101 storres
    # Compute the increment.
746 101 storres
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
747 81 storres
        currentScaledUpperBoundSa += \
748 101 storres
                        currentErrorRatio * boundsWidthSa * 2
749 101 storres
    else:  # [1, 1.5]
750 81 storres
        currentScaledUpperBoundSa += \
751 101 storres
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
752 101 storres
    # Take into account the original interval upper bound.
753 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
754 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
755 61 storres
    # Compute the other expansions.
756 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
757 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
758 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
759 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
760 60 storres
                                            currentScaledLowerBoundSa,
761 81 storres
                                            currentScaledUpperBoundSa,
762 81 storres
                                            approxPrecSa,
763 60 storres
                                            internalSollyaPrecSa)
764 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
765 101 storres
        if  errorSa < approxPrecSa:
766 101 storres
            # Change variable stuff
767 101 storres
            #print "Approximation error:", errorSa
768 101 storres
            changeVarExpressionSo = sollya_lib_build_function_sub(
769 101 storres
                                    sollya_lib_build_function_free_variable(),
770 101 storres
                                    sollya_lib_copy_obj(intervalCenterSo))
771 101 storres
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
772 115 storres
            sollya_lib_clear_obj(changeVarExpressionSo)
773 101 storres
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
774 101 storres
                                intervalCenterSo, maxErrorSo))
775 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
776 81 storres
        # Compute the next upper bound.
777 101 storres
        # The following ratio is always >= 1
778 81 storres
        currentErrorRatio = approxPrecSa / errorSa
779 101 storres
        # Starting point for the next upper bound.
780 101 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
781 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
782 101 storres
        # Compute the increment.
783 101 storres
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
784 101 storres
            currentScaledUpperBoundSa += \
785 101 storres
                            currentErrorRatio * boundsWidthSa * 2
786 101 storres
        else:  # [1, 1.5]
787 101 storres
            currentScaledUpperBoundSa += \
788 101 storres
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
789 101 storres
        #print "currentErrorRatio:", currentErrorRatio
790 101 storres
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
791 85 storres
        # Test for insufficient precision.
792 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
793 85 storres
            print "Can't shrink the interval anymore!"
794 85 storres
            print "You should consider increasing the Sollya internal precision"
795 85 storres
            print "or the polynomial degree."
796 85 storres
            print "Giving up!"
797 101 storres
            if internalSollyaPrecSa != currentSollyaPrecSa:
798 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
799 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
800 85 storres
            sollya_lib_clear_obj(functionSo)
801 85 storres
            sollya_lib_clear_obj(degreeSo)
802 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
803 85 storres
            return None
804 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
805 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
806 115 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
807 115 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
808 115 storres
    sollya_lib_clear_obj(currentSollyaPrecSo)
809 60 storres
    sollya_lib_clear_obj(functionSo)
810 60 storres
    sollya_lib_clear_obj(degreeSo)
811 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
812 60 storres
    return(resultArray)
813 81 storres
# End slz_get_intervals_and_polynomials
814 60 storres
815 81 storres
816 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
817 61 storres
    """
818 114 storres
    Compute the scaling expression to map an interval that span at most
819 114 storres
    a single binade to [1, 2) and the inverse expression as well.
820 62 storres
    Not very sure that the transformation makes sense for negative numbers.
821 61 storres
    """
822 62 storres
    # The scaling offset is only used for negative numbers.
823 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
824 61 storres
        if boundsInterval.endpoints()[0] >= 0:
825 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
826 62 storres
            invScalingCoeff = 1/scalingCoeff
827 80 storres
            return((scalingCoeff * expVar,
828 80 storres
                    invScalingCoeff * expVar))
829 60 storres
        else:
830 62 storres
            scalingCoeff = \
831 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
832 62 storres
            scalingOffset = -3 * scalingCoeff
833 80 storres
            return((scalingCoeff * expVar + scalingOffset,
834 80 storres
                    1/scalingCoeff * expVar + 3))
835 61 storres
    else:
836 61 storres
        if boundsInterval.endpoints()[0] >= 0:
837 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
838 61 storres
            scalingOffset = 0
839 80 storres
            return((scalingCoeff * expVar,
840 80 storres
                    1/scalingCoeff * expVar))
841 61 storres
        else:
842 62 storres
            scalingCoeff = \
843 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
844 62 storres
            scalingOffset =  -3 * scalingCoeff
845 62 storres
            #scalingOffset = 0
846 80 storres
            return((scalingCoeff * expVar + scalingOffset,
847 80 storres
                    1/scalingCoeff * expVar + 3))
848 61 storres
849 61 storres
850 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
851 72 storres
    """
852 72 storres
    Compute the Sage version of the Taylor polynomial and it's
853 72 storres
    companion data (interval, center...)
854 72 storres
    The input parameter is a five elements tuple:
855 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
856 79 storres
           real ring;
857 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
858 79 storres
           over a real ring;
859 72 storres
    - [2]: the interval (as Sollya range);
860 72 storres
    - [3]: the interval center;
861 72 storres
    - [4]: the approximation error.
862 72 storres
863 72 storres
    The function return a 5 elements tuple: formed with all the
864 72 storres
    input elements converted into their Sollya counterpart.
865 72 storres
    """
866 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
867 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
868 60 storres
    intervalSa = \
869 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
870 60 storres
    centerSa = \
871 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
872 60 storres
    errorSa = \
873 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
874 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
875 83 storres
    # End slz_interval_and_polynomial_to_sage
876 62 storres
877 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
878 80 storres
                                                precision,
879 80 storres
                                                targetHardnessToRound,
880 80 storres
                                                variable1,
881 80 storres
                                                variable2):
882 80 storres
    """
883 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
884 90 storres
     with the Coppersmith method.
885 80 storres
    A the same time it computes :
886 80 storres
    - 2^K (N);
887 90 storres
    - 2^k (bound on the second variable)
888 80 storres
    - lcm
889 90 storres
890 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
891 90 storres
                         variables.
892 90 storres
    :param precision: the precision of the floating-point coefficients.
893 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
894 90 storres
    :param variable1: the first variable of the polynomial (an expression).
895 90 storres
    :param variable2: the second variable of the polynomial (an expression).
896 90 storres
897 90 storres
    :returns: a 4 elements tuple:
898 90 storres
                - the polynomial;
899 91 storres
                - the modulus (N);
900 91 storres
                - the t bound;
901 90 storres
                - the lcm used to compute the integral coefficients and the
902 90 storres
                  module.
903 80 storres
    """
904 80 storres
    # Create a new integer polynomial ring.
905 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
906 80 storres
    # Coefficients are issued in the increasing power order.
907 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
908 91 storres
    # Print the reversed list for debugging.
909 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
910 94 storres
    # Build the list of number we compute the lcm of.
911 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
912 80 storres
    coefficientDenominators.append(2^precision)
913 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
914 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
915 80 storres
    # Compute the expression corresponding to the new polynomial
916 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
917 91 storres
    #print coefficientNumerators
918 80 storres
    polynomialExpression = 0
919 80 storres
    power = 0
920 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
921 80 storres
    # exhausted.
922 80 storres
    for numerator, denominator in \
923 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
924 80 storres
        multiplicator = leastCommonMultiple / denominator
925 80 storres
        newCoefficient = numerator * multiplicator
926 80 storres
        polynomialExpression += newCoefficient * variable1^power
927 80 storres
        power +=1
928 80 storres
    polynomialExpression += - variable2
929 80 storres
    return (IP(polynomialExpression),
930 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
931 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
932 91 storres
            leastCommonMultiple) # If we want to make test computations.
933 80 storres
934 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
935 79 storres
936 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
937 79 storres
                                          precision):
938 79 storres
    """
939 79 storres
    Makes a variable substitution into the input polynomial so that the output
940 79 storres
    polynomial can take integer arguments.
941 79 storres
    All variables of the input polynomial "have precision p". That is to say
942 103 storres
    that they are rationals with denominator == 2^(precision - 1):
943 103 storres
    x = y/2^(precision - 1).
944 79 storres
    We "incorporate" these denominators into the coefficients with,
945 79 storres
    respectively, the "right" power.
946 79 storres
    """
947 79 storres
    polynomialField = ratPolyOfRat.parent()
948 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
949 91 storres
    #print "The polynomial field is:", polynomialField
950 79 storres
    return \
951 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
952 79 storres
                                   polynomialVariable/2^(precision-1)}))
953 79 storres
954 79 storres
    # Return a tuple:
955 79 storres
    # - the bivariate integer polynomial in (i,j);
956 79 storres
    # - 2^K
957 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
958 79 storres
959 115 storres
960 87 storres
print "\t...sageSLZ loaded"
961 122 storres
print