Statistiques
| Révision :

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

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