Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (30,53 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 115 storres
#
90 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
91 119 storres
    """
92 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
93 121 storres
94 121 storres
    NOTE::
95 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
96 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
97 121 storres
        with interval [-infinity, -2^(emax+1)].
98 121 storres
99 119 storres
    """
100 121 storres
    # Check the parameters.
101 121 storres
    # RealNumbers only.
102 121 storres
    classTree = [number.__class__] + number.mro()
103 121 storres
    if not sage.rings.real_mpfr.RealNumber in classTree:
104 121 storres
        return None
105 121 storres
    # Non zero negative integers only for emin.
106 121 storres
    if emin >= 0 or int(emin) != emin:
107 121 storres
        return None
108 121 storres
    # Non zero positive integers only for emax.
109 121 storres
    if emax <= 0 or int(emax) != emax:
110 121 storres
        return None
111 121 storres
    precision = number.precision()
112 121 storres
    RF  = RealField(precision)
113 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
114 121 storres
    # when computing number.log2().
115 121 storres
    RRF = RealField(max(2048, 2 * precision))
116 121 storres
    # number = 0 special case, the binade bounds are
117 121 storres
    # [0, 2^emin - 2^(emin-precision)]
118 119 storres
    if number == 0:
119 119 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
120 121 storres
    # Begin general case
121 119 storres
    l2 = RRF(number).abs().log2()
122 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
123 121 storres
    if l2 >= emax + 1:
124 121 storres
        if number > 0:
125 121 storres
            return (RF(2^(emax+1)), RRR(+infinity) )
126 121 storres
        else:
127 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
128 119 storres
    offset = int(l2)
129 121 storres
    # number.abs() >= 1.
130 119 storres
    if l2 >= 0:
131 119 storres
        if number >= 0:
132 119 storres
            lb = RF(2^offset)
133 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
134 119 storres
        else: #number < 0
135 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
136 119 storres
            ub = -RF(2^offset)
137 121 storres
    else: # log2 < 0, number.abs() < 1.
138 119 storres
        if l2 < emin: # Denormal
139 121 storres
           # print "Denormal:", l2
140 119 storres
            if number >= 0:
141 119 storres
                lb = RF(0)
142 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
143 119 storres
            else: # number <= 0
144 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
145 119 storres
                ub = RF(0)
146 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
147 119 storres
            if number >= 0:
148 121 storres
                if int(l2) == l2:
149 121 storres
                    lb = RF(2^(offset))
150 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
151 121 storres
                else:
152 121 storres
                    lb = RF(2^(offset-1))
153 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
154 119 storres
            else: # number < 0
155 121 storres
                if int(l2) == l2: # Binade limit.
156 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
157 121 storres
                    ub = -RF(2^(offset))
158 121 storres
                else:
159 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
160 121 storres
                    ub = -RF(2^(offset-1))
161 121 storres
        else: # l2== emin, number == +/-2^emin
162 119 storres
            if number >= 0:
163 119 storres
                lb = RF(2^(offset))
164 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
165 119 storres
            else: # number < 0
166 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
167 119 storres
                ub = -RF(2^(offset))
168 119 storres
    return (lb, ub)
169 119 storres
# End slz_compute_binade_bounds
170 119 storres
#
171 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
172 61 storres
                                        upperBoundSa, approxPrecSa,
173 61 storres
                                        sollyaPrecSa=None):
174 61 storres
    """
175 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
176 61 storres
    a polynomial that approximates the function on a an interval starting
177 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
178 61 storres
    approximates with the expected precision.
179 61 storres
    The interval upper bound is lowered until the expected approximation
180 61 storres
    precision is reached.
181 61 storres
    The polynomial, the bounds, the center of the interval and the error
182 61 storres
    are returned.
183 61 storres
    """
184 61 storres
    RRR = lowerBoundSa.parent()
185 61 storres
    intervalShrinkConstFactorSa = RRR('0.5')
186 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
187 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
188 61 storres
    currentUpperBoundSa = upperBoundSa
189 61 storres
    currentLowerBoundSa = lowerBoundSa
190 61 storres
    # What we want here is the polynomial without the variable change,
191 61 storres
    # since our actual variable will be x-intervalCenter defined over the
192 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
193 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
194 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
195 61 storres
                                                    currentRangeSo,
196 61 storres
                                                    absoluteErrorTypeSo)
197 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
198 61 storres
    while maxErrorSa > approxPrecSa:
199 101 storres
        #print "++Approximation error:", maxErrorSa
200 81 storres
        sollya_lib_clear_obj(polySo)
201 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
202 120 storres
        sollya_lib_clear_obj(maxErrorSo)
203 101 storres
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
204 81 storres
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
205 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
206 61 storres
        #print "Error ratio: ", errorRatioSa
207 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
208 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
209 81 storres
            #print "Fixed"
210 61 storres
        else:
211 81 storres
            actualShrinkFactorSa = shrinkFactorSa
212 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
213 81 storres
            #print shrinkFactorSa, maxErrorSa
214 101 storres
        #print "Shrink factor", actualShrinkFactorSa
215 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
216 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
217 81 storres
                                   actualShrinkFactorSa
218 71 storres
        #print "Current upper bound:", currentUpperBoundSa
219 61 storres
        sollya_lib_clear_obj(currentRangeSo)
220 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
221 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
222 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
223 86 storres
            print "Can't find an interval."
224 86 storres
            print "Use either or both a higher polynomial degree or a higher",
225 86 storres
            print "internal precision."
226 86 storres
            print "Aborting!"
227 86 storres
            return (None, None, None, None)
228 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
229 61 storres
                                                      currentUpperBoundSa)
230 86 storres
        # print "New interval:",
231 86 storres
        # pobyso_autoprint(currentRangeSo)
232 120 storres
        #print "Second Taylor expansion call."
233 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
234 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
235 61 storres
                                                        currentRangeSo,
236 61 storres
                                                        absoluteErrorTypeSo)
237 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
238 85 storres
        #print "Max errorSo:",
239 85 storres
        #pobyso_autoprint(maxErrorSo)
240 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
241 85 storres
        #print "Max errorSa:", maxErrorSa
242 85 storres
        #print "Sollya prec:",
243 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
244 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
245 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
246 81 storres
# End slz_compute_polynomial_and_interval
247 61 storres
248 98 storres
def slz_compute_reduced_polynomials(reducedMatrix,
249 98 storres
                                    knownMonomials,
250 106 storres
                                    var1,
251 98 storres
                                    var1Bound,
252 106 storres
                                    var2,
253 99 storres
                                    var2Bound):
254 98 storres
    """
255 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
256 98 storres
    from the bounds of each variable, compute the corresponding polynomials
257 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
258 99 storres
259 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
260 103 storres
    They set the polynomial type of the output polynomials list.
261 98 storres
    """
262 99 storres
263 98 storres
    # TODO: check input arguments.
264 98 storres
    reducedPolynomials = []
265 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
266 98 storres
    for matrixRow in reducedMatrix.rows():
267 102 storres
        currentPolynomial = 0
268 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
269 98 storres
            currentCoefficient = matrixRow[colIndex]
270 106 storres
            if currentCoefficient != 0:
271 106 storres
                #print "Current coefficient:", currentCoefficient
272 106 storres
                currentMonomial = knownMonomials[colIndex]
273 106 storres
                parentRing = currentMonomial.parent()
274 106 storres
                #print "Monomial as multivariate polynomial:", \
275 106 storres
                #currentMonomial, type(currentMonomial)
276 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
277 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
278 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
279 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
280 106 storres
                if degreeInVar1 > 0:
281 106 storres
                    currentCoefficient = \
282 106 storres
                        currentCoefficient / var1Bound^degreeInVar1
283 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
284 106 storres
                    #print "Current coefficient(1)", currentCoefficient
285 106 storres
                if degreeInVar2 > 0:
286 106 storres
                    currentCoefficient = \
287 106 storres
                        currentCoefficient / var2Bound^degreeInVar2
288 106 storres
                    #print "Current coefficient(2)", currentCoefficient
289 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
290 106 storres
                #                                    currentMonomial)
291 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
292 106 storres
                #print "Current polynomial:", currentPolynomial
293 106 storres
            # End if
294 106 storres
        # End for colIndex.
295 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
296 99 storres
        reducedPolynomials.append(currentPolynomial)
297 98 storres
    return reducedPolynomials
298 99 storres
# End slz_compute_reduced_polynomials.
299 98 storres
300 114 storres
def slz_compute_scaled_function(functionSa,
301 114 storres
                                lowerBoundSa,
302 114 storres
                                upperBoundSa,
303 114 storres
                                floatingPointPrecSa):
304 72 storres
    """
305 72 storres
    From a function, compute the scaled function whose domain
306 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
307 72 storres
    Return a tuple:
308 72 storres
    [0]: the scaled function
309 72 storres
    [1]: the scaled domain lower bound
310 72 storres
    [2]: the scaled domain upper bound
311 72 storres
    [3]: the scaled image lower bound
312 72 storres
    [4]: the scaled image upper bound
313 72 storres
    """
314 80 storres
    x = functionSa.variables()[0]
315 80 storres
    # Reassert f as a function (an not a mere expression).
316 80 storres
317 72 storres
    # Scalling the domain -> [1,2[.
318 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
319 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
320 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
321 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
322 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
323 72 storres
    print "f: ", f
324 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
325 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
326 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
327 80 storres
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
328 80 storres
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
329 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
330 72 storres
    #
331 72 storres
    # Scalling the image -> [1,2[.
332 72 storres
    flbSa = f(lowerBoundSa).n()
333 72 storres
    fubSa = f(upperBoundSa).n()
334 72 storres
    if flbSa <= fubSa: # Increasing
335 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
336 72 storres
    else: # Decreasing
337 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
338 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
339 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
340 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
341 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
342 72 storres
    iis = invImageScalingExpressionSa.function(x)
343 72 storres
    fff = iis.subs({x:ff})
344 72 storres
    print "fff:", fff,
345 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
346 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
347 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
348 72 storres
349 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
350 79 storres
    # Create a polynomial over the rationals.
351 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
352 79 storres
    return(polynomialRing(polyOfFloat))
353 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
354 81 storres
355 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
356 63 storres
                                      lowerBoundSa,
357 60 storres
                                      upperBoundSa, floatingPointPrecSa,
358 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
359 60 storres
    """
360 60 storres
    Under the assumption that:
361 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
362 60 storres
    - lowerBound and upperBound belong to the same binade.
363 60 storres
    from a:
364 60 storres
    - function;
365 60 storres
    - a degree
366 60 storres
    - a pair of bounds;
367 60 storres
    - the floating-point precision we work on;
368 60 storres
    - the internal Sollya precision;
369 64 storres
    - the requested approximation error
370 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
371 61 storres
    It return a list of tuples, each made of:
372 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
373 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
374 61 storres
    - the approximation interval;
375 72 storres
    - the center, x0, of the interval;
376 61 storres
    - the corresponding approximation error.
377 100 storres
    TODO: fix endless looping for some parameters sets.
378 60 storres
    """
379 120 storres
    resultArray = []
380 101 storres
    # Set Sollya to the necessary internal precision.
381 120 storres
    precChangedSa = False
382 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
383 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
384 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
385 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
386 120 storres
        precChangedSa = True
387 101 storres
    #
388 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
389 101 storres
    # Scaled function: [1=,2] -> [1,2].
390 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
391 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
392 115 storres
                slz_compute_scaled_function(functionSa,                       \
393 115 storres
                                            lowerBoundSa,                     \
394 115 storres
                                            upperBoundSa,                     \
395 80 storres
                                            floatingPointPrecSa)
396 60 storres
    #
397 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
398 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
399 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
400 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
401 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
402 61 storres
                                                  scaledUpperBoundSa)
403 61 storres
    # Compute the first Taylor expansion.
404 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
405 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
406 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
407 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
408 86 storres
    if polySo is None:
409 101 storres
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
410 120 storres
        if precChangedSa:
411 120 storres
            pobyso_set_prec_so_so(currentSollyaPrecSo)
412 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
413 115 storres
        sollya_lib_clear_obj(functionSo)
414 115 storres
        sollya_lib_clear_obj(degreeSo)
415 115 storres
        sollya_lib_clear_obj(scaledBoundsSo)
416 86 storres
        return None
417 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
418 60 storres
                                              upperBoundSa.parent().precision()))
419 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
420 101 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
421 101 storres
    #print "First approximation error:", errorSa
422 101 storres
    # If the error and interval are OK a the first try, just return.
423 101 storres
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
424 101 storres
        # Change variable stuff in Sollya x -> x0-x.
425 101 storres
        changeVarExpressionSo = sollya_lib_build_function_sub( \
426 101 storres
                              sollya_lib_build_function_free_variable(), \
427 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
428 101 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
429 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
430 101 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
431 101 storres
                            intervalCenterSo, maxErrorSo))
432 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
433 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
434 115 storres
        sollya_lib_clear_obj(currentSollyaPrecSo)
435 101 storres
        sollya_lib_clear_obj(functionSo)
436 101 storres
        sollya_lib_clear_obj(degreeSo)
437 101 storres
        sollya_lib_clear_obj(scaledBoundsSo)
438 101 storres
        #print "Approximation error:", errorSa
439 101 storres
        return resultArray
440 120 storres
    # The returned interval upper bound does not reach the requested upper
441 120 storres
    # upper bound: compute the next upper bound.
442 101 storres
    # The following ratio is always >= 1
443 81 storres
    currentErrorRatio = approxPrecSa / errorSa
444 101 storres
    # Starting point for the next upper bound.
445 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
446 101 storres
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
447 101 storres
    # Compute the increment.
448 101 storres
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
449 81 storres
        currentScaledUpperBoundSa += \
450 101 storres
                        currentErrorRatio * boundsWidthSa * 2
451 101 storres
    else:  # [1, 1.5]
452 81 storres
        currentScaledUpperBoundSa += \
453 101 storres
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
454 101 storres
    # Take into account the original interval upper bound.
455 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
456 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
457 61 storres
    # Compute the other expansions.
458 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
459 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
460 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
461 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
462 60 storres
                                            currentScaledLowerBoundSa,
463 81 storres
                                            currentScaledUpperBoundSa,
464 81 storres
                                            approxPrecSa,
465 60 storres
                                            internalSollyaPrecSa)
466 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
467 101 storres
        if  errorSa < approxPrecSa:
468 101 storres
            # Change variable stuff
469 101 storres
            #print "Approximation error:", errorSa
470 101 storres
            changeVarExpressionSo = sollya_lib_build_function_sub(
471 101 storres
                                    sollya_lib_build_function_free_variable(),
472 101 storres
                                    sollya_lib_copy_obj(intervalCenterSo))
473 101 storres
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
474 115 storres
            sollya_lib_clear_obj(changeVarExpressionSo)
475 101 storres
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
476 101 storres
                                intervalCenterSo, maxErrorSo))
477 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
478 81 storres
        # Compute the next upper bound.
479 101 storres
        # The following ratio is always >= 1
480 81 storres
        currentErrorRatio = approxPrecSa / errorSa
481 101 storres
        # Starting point for the next upper bound.
482 101 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
483 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
484 101 storres
        # Compute the increment.
485 101 storres
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
486 101 storres
            currentScaledUpperBoundSa += \
487 101 storres
                            currentErrorRatio * boundsWidthSa * 2
488 101 storres
        else:  # [1, 1.5]
489 101 storres
            currentScaledUpperBoundSa += \
490 101 storres
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
491 101 storres
        #print "currentErrorRatio:", currentErrorRatio
492 101 storres
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
493 85 storres
        # Test for insufficient precision.
494 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
495 85 storres
            print "Can't shrink the interval anymore!"
496 85 storres
            print "You should consider increasing the Sollya internal precision"
497 85 storres
            print "or the polynomial degree."
498 85 storres
            print "Giving up!"
499 101 storres
            if internalSollyaPrecSa != currentSollyaPrecSa:
500 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
501 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
502 85 storres
            sollya_lib_clear_obj(functionSo)
503 85 storres
            sollya_lib_clear_obj(degreeSo)
504 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
505 85 storres
            return None
506 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
507 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
508 115 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
509 115 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
510 115 storres
    sollya_lib_clear_obj(currentSollyaPrecSo)
511 60 storres
    sollya_lib_clear_obj(functionSo)
512 60 storres
    sollya_lib_clear_obj(degreeSo)
513 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
514 60 storres
    return(resultArray)
515 81 storres
# End slz_get_intervals_and_polynomials
516 60 storres
517 81 storres
518 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
519 61 storres
    """
520 114 storres
    Compute the scaling expression to map an interval that span at most
521 114 storres
    a single binade to [1, 2) and the inverse expression as well.
522 62 storres
    Not very sure that the transformation makes sense for negative numbers.
523 61 storres
    """
524 62 storres
    # The scaling offset is only used for negative numbers.
525 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
526 61 storres
        if boundsInterval.endpoints()[0] >= 0:
527 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
528 62 storres
            invScalingCoeff = 1/scalingCoeff
529 80 storres
            return((scalingCoeff * expVar,
530 80 storres
                    invScalingCoeff * expVar))
531 60 storres
        else:
532 62 storres
            scalingCoeff = \
533 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
534 62 storres
            scalingOffset = -3 * scalingCoeff
535 80 storres
            return((scalingCoeff * expVar + scalingOffset,
536 80 storres
                    1/scalingCoeff * expVar + 3))
537 61 storres
    else:
538 61 storres
        if boundsInterval.endpoints()[0] >= 0:
539 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
540 61 storres
            scalingOffset = 0
541 80 storres
            return((scalingCoeff * expVar,
542 80 storres
                    1/scalingCoeff * expVar))
543 61 storres
        else:
544 62 storres
            scalingCoeff = \
545 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
546 62 storres
            scalingOffset =  -3 * scalingCoeff
547 62 storres
            #scalingOffset = 0
548 80 storres
            return((scalingCoeff * expVar + scalingOffset,
549 80 storres
                    1/scalingCoeff * expVar + 3))
550 61 storres
551 61 storres
552 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
553 72 storres
    """
554 72 storres
    Compute the Sage version of the Taylor polynomial and it's
555 72 storres
    companion data (interval, center...)
556 72 storres
    The input parameter is a five elements tuple:
557 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
558 79 storres
           real ring;
559 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
560 79 storres
           over a real ring;
561 72 storres
    - [2]: the interval (as Sollya range);
562 72 storres
    - [3]: the interval center;
563 72 storres
    - [4]: the approximation error.
564 72 storres
565 72 storres
    The function return a 5 elements tuple: formed with all the
566 72 storres
    input elements converted into their Sollya counterpart.
567 72 storres
    """
568 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
569 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
570 60 storres
    intervalSa = \
571 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
572 60 storres
    centerSa = \
573 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
574 60 storres
    errorSa = \
575 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
576 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
577 83 storres
    # End slz_interval_and_polynomial_to_sage
578 62 storres
579 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
580 80 storres
                                                precision,
581 80 storres
                                                targetHardnessToRound,
582 80 storres
                                                variable1,
583 80 storres
                                                variable2):
584 80 storres
    """
585 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
586 90 storres
     with the Coppersmith method.
587 80 storres
    A the same time it computes :
588 80 storres
    - 2^K (N);
589 90 storres
    - 2^k (bound on the second variable)
590 80 storres
    - lcm
591 90 storres
592 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
593 90 storres
                         variables.
594 90 storres
    :param precision: the precision of the floating-point coefficients.
595 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
596 90 storres
    :param variable1: the first variable of the polynomial (an expression).
597 90 storres
    :param variable2: the second variable of the polynomial (an expression).
598 90 storres
599 90 storres
    :returns: a 4 elements tuple:
600 90 storres
                - the polynomial;
601 91 storres
                - the modulus (N);
602 91 storres
                - the t bound;
603 90 storres
                - the lcm used to compute the integral coefficients and the
604 90 storres
                  module.
605 80 storres
    """
606 80 storres
    # Create a new integer polynomial ring.
607 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
608 80 storres
    # Coefficients are issued in the increasing power order.
609 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
610 91 storres
    # Print the reversed list for debugging.
611 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
612 94 storres
    # Build the list of number we compute the lcm of.
613 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
614 80 storres
    coefficientDenominators.append(2^precision)
615 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
616 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
617 80 storres
    # Compute the expression corresponding to the new polynomial
618 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
619 91 storres
    #print coefficientNumerators
620 80 storres
    polynomialExpression = 0
621 80 storres
    power = 0
622 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
623 80 storres
    # exhausted.
624 80 storres
    for numerator, denominator in \
625 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
626 80 storres
        multiplicator = leastCommonMultiple / denominator
627 80 storres
        newCoefficient = numerator * multiplicator
628 80 storres
        polynomialExpression += newCoefficient * variable1^power
629 80 storres
        power +=1
630 80 storres
    polynomialExpression += - variable2
631 80 storres
    return (IP(polynomialExpression),
632 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
633 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
634 91 storres
            leastCommonMultiple) # If we want to make test computations.
635 80 storres
636 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
637 79 storres
638 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
639 79 storres
                                          precision):
640 79 storres
    """
641 79 storres
    Makes a variable substitution into the input polynomial so that the output
642 79 storres
    polynomial can take integer arguments.
643 79 storres
    All variables of the input polynomial "have precision p". That is to say
644 103 storres
    that they are rationals with denominator == 2^(precision - 1):
645 103 storres
    x = y/2^(precision - 1).
646 79 storres
    We "incorporate" these denominators into the coefficients with,
647 79 storres
    respectively, the "right" power.
648 79 storres
    """
649 79 storres
    polynomialField = ratPolyOfRat.parent()
650 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
651 91 storres
    #print "The polynomial field is:", polynomialField
652 79 storres
    return \
653 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
654 79 storres
                                   polynomialVariable/2^(precision-1)}))
655 79 storres
656 79 storres
    # Return a tuple:
657 79 storres
    # - the bivariate integer polynomial in (i,j);
658 79 storres
    # - 2^K
659 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
660 79 storres
661 115 storres
662 87 storres
print "\t...sageSLZ loaded"