Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (28,96 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 61 storres
        sollya_lib_clear_obj(maxErrorSo)
166 81 storres
        sollya_lib_clear_obj(polySo)
167 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
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 61 storres
        sollya_lib_clear_obj(polySo)
186 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
187 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
188 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
189 86 storres
            print "Can't find an interval."
190 86 storres
            print "Use either or both a higher polynomial degree or a higher",
191 86 storres
            print "internal precision."
192 86 storres
            print "Aborting!"
193 86 storres
            return (None, None, None, None)
194 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
195 61 storres
                                                      currentUpperBoundSa)
196 86 storres
        # print "New interval:",
197 86 storres
        # pobyso_autoprint(currentRangeSo)
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 101 storres
    # Set Sollya to the necessary internal precision.
345 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
346 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
347 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
348 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
349 101 storres
    #
350 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
351 101 storres
    # Scaled function: [1=,2] -> [1,2].
352 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
353 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
354 115 storres
                slz_compute_scaled_function(functionSa,                       \
355 115 storres
                                            lowerBoundSa,                     \
356 115 storres
                                            upperBoundSa,                     \
357 80 storres
                                            floatingPointPrecSa)
358 60 storres
    #
359 60 storres
    resultArray = []
360 60 storres
    #
361 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
362 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
363 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
364 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
365 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
366 61 storres
                                                  scaledUpperBoundSa)
367 61 storres
    # Compute the first Taylor expansion.
368 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
369 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
370 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
371 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
372 86 storres
    if polySo is None:
373 101 storres
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
374 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
375 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
376 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
377 115 storres
        sollya_lib_clear_obj(functionSo)
378 115 storres
        sollya_lib_clear_obj(degreeSo)
379 115 storres
        sollya_lib_clear_obj(scaledBoundsSo)
380 86 storres
        return None
381 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
382 60 storres
                                              upperBoundSa.parent().precision()))
383 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
384 101 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
385 101 storres
    #print "First approximation error:", errorSa
386 101 storres
    # If the error and interval are OK a the first try, just return.
387 101 storres
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
388 101 storres
        # Change variable stuff in Sollya x -> x0-x.
389 101 storres
        changeVarExpressionSo = sollya_lib_build_function_sub( \
390 101 storres
                              sollya_lib_build_function_free_variable(), \
391 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
392 101 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
393 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
394 101 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
395 101 storres
                            intervalCenterSo, maxErrorSo))
396 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
397 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
398 115 storres
        sollya_lib_clear_obj(currentSollyaPrecSo)
399 101 storres
        sollya_lib_clear_obj(functionSo)
400 101 storres
        sollya_lib_clear_obj(degreeSo)
401 101 storres
        sollya_lib_clear_obj(scaledBoundsSo)
402 101 storres
        #print "Approximation error:", errorSa
403 101 storres
        return resultArray
404 81 storres
    # Compute the next upper bound.
405 101 storres
    # The following ratio is always >= 1
406 81 storres
    currentErrorRatio = approxPrecSa / errorSa
407 101 storres
    # Starting point for the next upper bound.
408 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
409 101 storres
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
410 101 storres
    # Compute the increment.
411 101 storres
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
412 81 storres
        currentScaledUpperBoundSa += \
413 101 storres
                        currentErrorRatio * boundsWidthSa * 2
414 101 storres
    else:  # [1, 1.5]
415 81 storres
        currentScaledUpperBoundSa += \
416 101 storres
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
417 101 storres
    # Take into account the original interval upper bound.
418 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
419 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
420 61 storres
    # Compute the other expansions.
421 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
422 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
423 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
424 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
425 60 storres
                                            currentScaledLowerBoundSa,
426 81 storres
                                            currentScaledUpperBoundSa,
427 81 storres
                                            approxPrecSa,
428 60 storres
                                            internalSollyaPrecSa)
429 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
430 101 storres
        if  errorSa < approxPrecSa:
431 101 storres
            # Change variable stuff
432 101 storres
            #print "Approximation error:", errorSa
433 101 storres
            changeVarExpressionSo = sollya_lib_build_function_sub(
434 101 storres
                                    sollya_lib_build_function_free_variable(),
435 101 storres
                                    sollya_lib_copy_obj(intervalCenterSo))
436 101 storres
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
437 115 storres
            sollya_lib_clear_obj(changeVarExpressionSo)
438 101 storres
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
439 101 storres
                                intervalCenterSo, maxErrorSo))
440 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
441 81 storres
        # 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 101 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 101 storres
            currentScaledUpperBoundSa += \
450 101 storres
                            currentErrorRatio * boundsWidthSa * 2
451 101 storres
        else:  # [1, 1.5]
452 101 storres
            currentScaledUpperBoundSa += \
453 101 storres
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
454 101 storres
        #print "currentErrorRatio:", currentErrorRatio
455 101 storres
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
456 85 storres
        # Test for insufficient precision.
457 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
458 85 storres
            print "Can't shrink the interval anymore!"
459 85 storres
            print "You should consider increasing the Sollya internal precision"
460 85 storres
            print "or the polynomial degree."
461 85 storres
            print "Giving up!"
462 101 storres
            if internalSollyaPrecSa != currentSollyaPrecSa:
463 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
464 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
465 85 storres
            sollya_lib_clear_obj(functionSo)
466 85 storres
            sollya_lib_clear_obj(degreeSo)
467 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
468 85 storres
            return None
469 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
470 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
471 115 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
472 115 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
473 115 storres
    sollya_lib_clear_obj(currentSollyaPrecSo)
474 60 storres
    sollya_lib_clear_obj(functionSo)
475 60 storres
    sollya_lib_clear_obj(degreeSo)
476 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
477 60 storres
    return(resultArray)
478 81 storres
# End slz_get_intervals_and_polynomials
479 60 storres
480 81 storres
481 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
482 61 storres
    """
483 114 storres
    Compute the scaling expression to map an interval that span at most
484 114 storres
    a single binade to [1, 2) and the inverse expression as well.
485 62 storres
    Not very sure that the transformation makes sense for negative numbers.
486 61 storres
    """
487 62 storres
    # The scaling offset is only used for negative numbers.
488 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
489 61 storres
        if boundsInterval.endpoints()[0] >= 0:
490 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
491 62 storres
            invScalingCoeff = 1/scalingCoeff
492 80 storres
            return((scalingCoeff * expVar,
493 80 storres
                    invScalingCoeff * expVar))
494 60 storres
        else:
495 62 storres
            scalingCoeff = \
496 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
497 62 storres
            scalingOffset = -3 * scalingCoeff
498 80 storres
            return((scalingCoeff * expVar + scalingOffset,
499 80 storres
                    1/scalingCoeff * expVar + 3))
500 61 storres
    else:
501 61 storres
        if boundsInterval.endpoints()[0] >= 0:
502 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
503 61 storres
            scalingOffset = 0
504 80 storres
            return((scalingCoeff * expVar,
505 80 storres
                    1/scalingCoeff * expVar))
506 61 storres
        else:
507 62 storres
            scalingCoeff = \
508 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
509 62 storres
            scalingOffset =  -3 * scalingCoeff
510 62 storres
            #scalingOffset = 0
511 80 storres
            return((scalingCoeff * expVar + scalingOffset,
512 80 storres
                    1/scalingCoeff * expVar + 3))
513 61 storres
514 61 storres
515 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
516 72 storres
    """
517 72 storres
    Compute the Sage version of the Taylor polynomial and it's
518 72 storres
    companion data (interval, center...)
519 72 storres
    The input parameter is a five elements tuple:
520 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
521 79 storres
           real ring;
522 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
523 79 storres
           over a real ring;
524 72 storres
    - [2]: the interval (as Sollya range);
525 72 storres
    - [3]: the interval center;
526 72 storres
    - [4]: the approximation error.
527 72 storres
528 72 storres
    The function return a 5 elements tuple: formed with all the
529 72 storres
    input elements converted into their Sollya counterpart.
530 72 storres
    """
531 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
532 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
533 60 storres
    intervalSa = \
534 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
535 60 storres
    centerSa = \
536 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
537 60 storres
    errorSa = \
538 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
539 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
540 83 storres
    # End slz_interval_and_polynomial_to_sage
541 62 storres
542 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
543 80 storres
                                                precision,
544 80 storres
                                                targetHardnessToRound,
545 80 storres
                                                variable1,
546 80 storres
                                                variable2):
547 80 storres
    """
548 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
549 90 storres
     with the Coppersmith method.
550 80 storres
    A the same time it computes :
551 80 storres
    - 2^K (N);
552 90 storres
    - 2^k (bound on the second variable)
553 80 storres
    - lcm
554 90 storres
555 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
556 90 storres
                         variables.
557 90 storres
    :param precision: the precision of the floating-point coefficients.
558 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
559 90 storres
    :param variable1: the first variable of the polynomial (an expression).
560 90 storres
    :param variable2: the second variable of the polynomial (an expression).
561 90 storres
562 90 storres
    :returns: a 4 elements tuple:
563 90 storres
                - the polynomial;
564 91 storres
                - the modulus (N);
565 91 storres
                - the t bound;
566 90 storres
                - the lcm used to compute the integral coefficients and the
567 90 storres
                  module.
568 80 storres
    """
569 80 storres
    # Create a new integer polynomial ring.
570 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
571 80 storres
    # Coefficients are issued in the increasing power order.
572 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
573 91 storres
    # Print the reversed list for debugging.
574 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
575 94 storres
    # Build the list of number we compute the lcm of.
576 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
577 80 storres
    coefficientDenominators.append(2^precision)
578 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
579 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
580 80 storres
    # Compute the expression corresponding to the new polynomial
581 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
582 91 storres
    #print coefficientNumerators
583 80 storres
    polynomialExpression = 0
584 80 storres
    power = 0
585 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
586 80 storres
    # exhausted.
587 80 storres
    for numerator, denominator in \
588 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
589 80 storres
        multiplicator = leastCommonMultiple / denominator
590 80 storres
        newCoefficient = numerator * multiplicator
591 80 storres
        polynomialExpression += newCoefficient * variable1^power
592 80 storres
        power +=1
593 80 storres
    polynomialExpression += - variable2
594 80 storres
    return (IP(polynomialExpression),
595 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
596 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
597 91 storres
            leastCommonMultiple) # If we want to make test computations.
598 80 storres
599 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
600 79 storres
601 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
602 79 storres
                                          precision):
603 79 storres
    """
604 79 storres
    Makes a variable substitution into the input polynomial so that the output
605 79 storres
    polynomial can take integer arguments.
606 79 storres
    All variables of the input polynomial "have precision p". That is to say
607 103 storres
    that they are rationals with denominator == 2^(precision - 1):
608 103 storres
    x = y/2^(precision - 1).
609 79 storres
    We "incorporate" these denominators into the coefficients with,
610 79 storres
    respectively, the "right" power.
611 79 storres
    """
612 79 storres
    polynomialField = ratPolyOfRat.parent()
613 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
614 91 storres
    #print "The polynomial field is:", polynomialField
615 79 storres
    return \
616 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
617 79 storres
                                   polynomialVariable/2^(precision-1)}))
618 79 storres
619 79 storres
    # Return a tuple:
620 79 storres
    # - the bivariate integer polynomial in (i,j);
621 79 storres
    # - 2^K
622 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
623 79 storres
624 115 storres
625 87 storres
print "\t...sageSLZ loaded"