Statistiques
| Révision :

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

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