Statistiques
| Révision :

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

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

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

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

    
264
print "sageSLZ loaded..."