Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (14,46 ko)

1
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa, 
2
                                        upperBoundSa, approxPrecSa, 
3
                                        sollyaPrecSa=None):
4
    """
5
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
6
    a polynomial that approximates the function on a an interval starting
7
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
8
    approximates with the expected precision.
9
    The interval upper bound is lowered until the expected approximation 
10
    precision is reached.
11
    The polynomial, the bounds, the center of the interval and the error
12
    are returned.
13
    """
14
    RRR = lowerBoundSa.parent()
15
    #goldenRatioSa = RRR(5.sqrt() / 2 - 1/2)
16
    #intervalShrinkConstFactorSa = goldenRatioSa
17
    intervalShrinkConstFactorSa = RRR('0.5')
18
    absoluteErrorTypeSo = pobyso_absolute_so_so()
19
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
20
    currentUpperBoundSa = upperBoundSa
21
    currentLowerBoundSa = lowerBoundSa
22
    # What we want here is the polynomial without the variable change, 
23
    # since our actual variable will be x-intervalCenter defined over the 
24
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
25
    (polySo, intervalCenterSo, maxErrorSo) = \
26
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
27
                                                    currentRangeSo, 
28
                                                    absoluteErrorTypeSo)
29
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
30
    while maxErrorSa > approxPrecSa:
31
        sollya_lib_clear_obj(maxErrorSo)
32
        errorRatioSa = 1/(maxErrorSa/approxPrecSa).log2()
33
        #print "Error ratio: ", errorRatioSa
34
        if errorRatioSa > intervalShrinkConstFactorSa:
35
            currentUpperBoundSa = currentLowerBoundSa + \
36
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
37
                                   intervalShrinkConstFactorSa
38
        else:
39
            currentUpperBoundSa = currentLowerBoundSa + \
40
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
41
                                  intervalShrinkConstFactorSa
42
            currentUpperBoundSa = currentLowerBoundSa + \
43
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
44
                                  errorRatioSa
45
        #print "Current upper bound:", currentUpperBoundSa
46
        sollya_lib_clear_obj(currentRangeSo)
47
        sollya_lib_clear_obj(polySo)
48
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
49
                                                      currentUpperBoundSa)
50
        (polySo, intervalCenterSo, maxErrorSo) = \
51
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
52
                                                        currentRangeSo, 
53
                                                        absoluteErrorTypeSo)
54
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
55
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
56
    sollya_lib_clear_obj(absoluteErrorTypeSo)
57
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
58
    # End slz_compute_polynomial_and_interval
59

    
60
def slz_compute_scaled_function(functionSa, \
61
                                      variableNameSa, \
62
                                      lowerBoundSa, \
63
                                      upperBoundSa, \
64
                                      floatingPointPrecSa):
65
    """
66
    From a function, compute the scaled function whose domain
67
    is included in [1, 2) and whose image is also included in [1,2).
68
    Return a tuple: 
69
    [0]: the scaled function
70
    [1]: the scaled domain lower bound
71
    [2]: the scaled domain upper bound
72
    [3]: the scaled image lower bound
73
    [4]: the scaled image upper bound
74
    """
75
    x = var(variableNameSa)
76
    # Scalling the domain -> [1,2[.
77
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
78
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
79
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
80
        slz_interval_scaling_expression(domainBoundsIntervalSa, variableNameSa)
81
    print "domainScalingExpression for argument :", domainScalingExpressionSa
82
    print "f: ", f
83
    ff = f.subs({x : domainScalingExpressionSa})
84
    #ff = f.subs_expr(x==domainScalingExpressionSa)
85
    scaledLowerBoundSa = invDomainScalingExpressionSa(lowerBoundSa).n()
86
    scaledUpperBoundSa = invDomainScalingExpressionSa(upperBoundSa).n()
87
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
88
    #
89
    # Scalling the image -> [1,2[.
90
    flbSa = f(lowerBoundSa).n()
91
    fubSa = f(upperBoundSa).n()
92
    if flbSa <= fubSa: # Increasing
93
        imageBinadeBottomSa = floor(flbSa.log2())
94
    else: # Decreasing
95
        imageBinadeBottomSa = floor(fubSa.log2())
96
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
97
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
98
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
99
        slz_interval_scaling_expression(imageBoundsIntervalSa, variableNameSa)
100
    iis = invImageScalingExpressionSa.function(x)
101
    fff = iis.subs({x:ff})
102
    print "fff:", fff,
103
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
104
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
105
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
106

    
107
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
108
    # Create a polynomial over the rationals.
109
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
110
    return(polynomialRing(polyOfFloat))
111
# End slz_float_poly_of_float_to_rat_poly_of_rat
112
     
113
def slz_get_intervals_and_polynomials(functionSa, variableNameSa, degreeSa, 
114
                                      lowerBoundSa, 
115
                                      upperBoundSa, floatingPointPrecSa, 
116
                                      internalSollyaPrecSa, approxPrecSa):
117
    """
118
    Under the assumption that:
119
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
120
    - lowerBound and upperBound belong to the same binade.
121
    from a:
122
    - function;
123
    - a degree
124
    - a pair of bounds;
125
    - the floating-point precision we work on;
126
    - the internal Sollya precision;
127
    - the requested approximation error
128
    The initial interval is, possibly, splitted into smaller intervals.
129
    It return a list of tuples, each made of:
130
    - a first polynomial (without the changed variable f(x) = p(x-x0));
131
    - a second polynomial (with a changed variable f(x) = q(x))
132
    - the approximation interval;
133
    - the center, x0, of the interval;
134
    - the corresponding approximation error.
135
    """
136
    x = var(variableNameSa)
137
    # Scalling the domain -> [1,2[.
138
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
139
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
140
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
141
        slz_interval_scaling_expression(domainBoundsIntervalSa, variableNameSa)
142
    print "domainScalingExpression for argument :", domainScalingExpressionSa
143
    print "f: ", f
144
    ff = f.subs({x : domainScalingExpressionSa})
145
    #ff = f.subs_expr(x==domainScalingExpressionSa)
146
    scaledLowerBoundSa = invDomainScalingExpressionSa(lowerBoundSa).n()
147
    scaledUpperBoundSa = invDomainScalingExpressionSa(upperBoundSa).n()
148
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
149
    #
150
    # Scalling the image -> [1,2[.
151
    flbSa = f(lowerBoundSa).n()
152
    fubSa = f(upperBoundSa).n()
153
    if flbSa <= fubSa: # Increasing
154
        imageBinadeBottomSa = floor(flbSa.log2())
155
    else: # Decreasing
156
        imageBinadeBottomSa = floor(fubSa.log2())
157
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
158
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
159
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
160
        slz_interval_scaling_expression(imageBoundsIntervalSa, variableNameSa)
161
    iis = invImageScalingExpressionSa.function(x)
162
    fff = iis.subs({x:ff})
163
    print "fff:", fff,
164
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
165
    #
166
    resultArray = []
167
    #
168
    print "Approximation precision: ", RR(approxPrecSa)
169
    # Prepare the arguments for the Taylor expansion computation with Sollya.
170
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
171
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
172
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
173
                                                  scaledUpperBoundSa)
174
    # Compute the first Taylor expansion.
175
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
176
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
177
                                        scaledLowerBoundSa, scaledUpperBoundSa,
178
                                        approxPrecSa, internalSollyaPrecSa)
179
    # Change variable stuff
180
    changeVarExpressionSo = sollya_lib_build_function_sub(
181
                              sollya_lib_build_function_free_variable(), 
182
                              sollya_lib_copy_obj(intervalCenterSo))
183
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
184
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
185
                         maxErrorSo))
186
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
187
                                              upperBoundSa.parent().precision()))
188
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
189
    # Compute the other expansions.
190
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
191
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
192
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
193
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
194
                                            currentScaledLowerBoundSa, 
195
                                            scaledUpperBoundSa, approxPrecSa, 
196
                                            internalSollyaPrecSa)
197
        # Change variable stuff
198
        changeVarExpressionSo = sollya_lib_build_function_sub(
199
                                  sollya_lib_build_function_free_variable(), 
200
                                  sollya_lib_copy_obj(intervalCenterSo))
201
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
202
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
203
                            intervalCenterSo, maxErrorSo))
204
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
205
    sollya_lib_clear_obj(functionSo)
206
    sollya_lib_clear_obj(degreeSo)
207
    sollya_lib_clear_obj(scaledBoundsSo)
208
    return(resultArray)
209
    # End slz_get_intervals_and_polynomials
210

    
211
def slz_interval_scaling_expression(boundsInterval, varName):
212
    """
213
    Compute the scaling expression to map an interval that span only
214
    a binade to [1, 2) and the inverse expression as well.
215
    Not very sure that the transformation makes sense for negative numbers.
216
    """
217
    # The scaling offset is only used for negative numbers.
218
    if abs(boundsInterval.endpoints()[0]) < 1:
219
        if boundsInterval.endpoints()[0] >= 0:
220
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
221
            invScalingCoeff = 1/scalingCoeff
222
            return((scalingCoeff * eval(varName), 
223
                    invScalingCoeff * eval(varName)))
224
        else:
225
            scalingCoeff = \
226
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
227
            scalingOffset = -3 * scalingCoeff
228
            return((scalingCoeff * eval(varName) + scalingOffset,
229
                    1/scalingCoeff * eval(varName) + 3))
230
    else: 
231
        if boundsInterval.endpoints()[0] >= 0:
232
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
233
            scalingOffset = 0
234
            return((scalingCoeff * eval(varName), 
235
                    1/scalingCoeff * eval(varName)))
236
        else:
237
            scalingCoeff = \
238
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
239
            scalingOffset =  -3 * scalingCoeff
240
            #scalingOffset = 0
241
            return((scalingCoeff * eval(varName) + scalingOffset,
242
                    1/scalingCoeff * eval(varName) + 3))
243

    
244
   
245
def slz_polynomial_and_interval_to_sage(polyRangeCenterErrorSo):
246
    """
247
    Compute the Sage version of the Taylor polynomial and it's
248
    companion data (interval, center...)
249
    The input parameter is a five elements tuple:
250
    - [0]: the polyomial (without variable change), as polynomial over a
251
           real ring;
252
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
253
           over a real ring;
254
    - [2]: the interval (as Sollya range);
255
    - [3]: the interval center;
256
    - [4]: the approximation error. 
257
    
258
    The function return a 5 elements tuple: formed with all the 
259
    input elements converted into their Sollya counterpart.
260
    """
261
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
262
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
263
    intervalSa = \
264
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
265
    centerSa = \
266
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
267
    errorSa = \
268
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
269
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
270
    # End slz_polynomial_and_interval_to_sage
271

    
272
def slz_rat_poly_of_int_to_int_poly_of_int(ratPolyOfInt):
273
    pass
274
# End slz_ratPoly_of_int_to_int_poly_of_int
275

    
276
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
277
                                          precision):
278
    """
279
    Makes a variable substitution into the input polynomial so that the output
280
    polynomial can take integer arguments.
281
    All variables of the input polynomial "have precision p". That is to say
282
    that they are rationals with denominator == 2^precision: x = y/2^precision
283
    We "incorporate" these denominators into the coefficients with, 
284
    respectively, the "right" power.
285
    """
286
    polynomialField = ratPolyOfRat.parent()
287
    polynomialVariable = rationalPolynomial.variables()[0]
288
    print "The polynomial field is:", polynomialField
289
    return \
290
        polynomialField(rationalPolynomial.subs({polynomialVariable : \
291
                                   polynomialVariable/2^(precision-1)}))
292
    
293
    # Return a tuple:
294
    # - the bivariate integer polynomial in (i,j);
295
    # - 2^K
296
# End slz_rat_poly_of_rat_to_rat_poly_of_int
297

    
298
print "sageSLZ loaded..."