Statistiques
| Révision :

root / pobysoPythonSage / src / sageSLZ.sage @ 65

Historique | Voir | Annoter | Télécharger (10,53 ko)

1

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

    
59
def slz_get_intervals_and_polynomials(functionSa, variableNameSa, degreeSa, 
60
                                      lowerBoundSa, 
61
                                      upperBoundSa, floatingPointPrecSa, 
62
                                      internalSollyaPrecSa, approxPrecSa):
63
    """
64
    Under the assumption that:
65
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
66
    - lowerBound and upperBound belong to the same binade.
67
    from a:
68
    - function;
69
    - a degree
70
    - a pair of bounds;
71
    - the floating-point precision we work on;
72
    - the internal Sollya precision;
73
    - the requested approximation error
74
    compute a list of tuples made of:
75
    - a polynomial approximating the function (a Sollya object);
76
    - the range for which the polynomial approximates the function 
77
      (a Sollya object);
78
    - the center of the interval (a Sollya object);
79
    - the actual approximation error (a Sage object). 
80
    The initial interval is, possibly, splitted into smaller intervals.
81
    It return a list of tuples, each made of:
82
    - a polynomial;
83
    - the approximation interval;
84
    - the center, x0,  of the interval (the polynomial is defined as p(x-x0));
85
    - the corresponding approximation error.
86
    """
87
    x = var(variableNameSa)
88
    # Scalling the domain -> [1,2[.
89
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
90
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
91
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
92
        slz_interval_scaling_expression(domainBoundsIntervalSa, variableNameSa)
93
    print "domainScalingExpression for argument :", domainScalingExpressionSa
94
    print "f: ", f
95
    ff = f.subs({x : domainScalingExpressionSa})
96
    #ff = f.subs_expr(x==domainScalingExpressionSa)
97
    scaledLowerBoundSa = invDomainScalingExpressionSa(lowerBoundSa).n()
98
    scaledUpperBoundSa = invDomainScalingExpressionSa(upperBoundSa).n()
99
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
100
    #
101
    # Scalling the image -> [1,2[.
102
    flbSa = f(lowerBoundSa).n()
103
    fubSa = f(upperBoundSa).n()
104
    if flbSa <= fubSa: # Increasing
105
        imageBinadeBottomSa = floor(flbSa.log2())
106
    else: # Decreasing
107
        imageBinadeBottomSa = floor(fubSa.log2())
108
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
109
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
110
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
111
        slz_interval_scaling_expression(imageBoundsIntervalSa, variableNameSa)
112
    iis = invImageScalingExpressionSa.function(x)
113
    fff = iis.subs({x:ff})
114
    print "fff:", fff,
115
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
116
    #
117
    resultArray = []
118
    #
119
    print "Approximation precision: ", RR(approxPrecSa)
120
    # Prepare the arguments for the Taylor expansion computation with Sollya.
121
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
122
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
123
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
124
                                                  scaledUpperBoundSa)
125
    # Compute the first Taylor expansion.
126
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
127
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
128
                                        scaledLowerBoundSa, scaledUpperBoundSa,
129
                                        approxPrecSa, internalSollyaPrecSa)
130
    # Change variable stuff
131
    changeVarExpressionSo = sollya_lib_build_function_sub(
132
                              sollya_lib_build_function_free_variable(), 
133
                              sollya_lib_copy_obj(intervalCenterSo))
134
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
135
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
136
                         maxErrorSo))
137
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
138
                                              upperBoundSa.parent().precision()))
139
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
140
    # Compute the other expansions.
141
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
142
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
143
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
144
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
145
                                            currentScaledLowerBoundSa, 
146
                                            scaledUpperBoundSa, approxPrecSa, 
147
                                            internalSollyaPrecSa)
148
        # Change variable stuff
149
        changeVarExpressionSo = sollya_lib_build_function_sub(
150
                                  sollya_lib_build_function_free_variable(), 
151
                                  sollya_lib_copy_obj(intervalCenterSo))
152
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
153
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
154
                            intervalCenterSo, maxErrorSo))
155
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
156
    sollya_lib_clear_obj(functionSo)
157
    sollya_lib_clear_obj(degreeSo)
158
    sollya_lib_clear_obj(scaledBoundsSo)
159
    return(resultArray)
160
    # End slz_get_intervals_and_polynomials
161

    
162
def slz_interval_scaling_expression(boundsInterval, varName):
163
    """
164
    Compute the scaling expression to map an interval that span only
165
    a binade to [1, 2) and the inverse expression as well.
166
    Not very sure that the transformation makes sense for negative numbers.
167
    """
168
    # The scaling offset is only used for negative numbers.
169
    if abs(boundsInterval.endpoints()[0]) < 1:
170
        if boundsInterval.endpoints()[0] >= 0:
171
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
172
            invScalingCoeff = 1/scalingCoeff
173
            return((scalingCoeff * eval(varName), 
174
                    invScalingCoeff * eval(varName)))
175
        else:
176
            scalingCoeff = \
177
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
178
            scalingOffset = -3 * scalingCoeff
179
            return((scalingCoeff * eval(varName) + scalingOffset,
180
                    1/scalingCoeff * eval(varName) + 3))
181
    else: 
182
        if boundsInterval.endpoints()[0] >= 0:
183
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
184
            scalingOffset = 0
185
            return((scalingCoeff * eval(varName), 
186
                    1/scalingCoeff * eval(varName)))
187
        else:
188
            scalingCoeff = \
189
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
190
            scalingOffset =  -3 * scalingCoeff
191
            #scalingOffset = 0
192
            return((scalingCoeff * eval(varName) + scalingOffset,
193
                    1/scalingCoeff * eval(varName) + 3))
194

    
195
   
196
def slz_polynomial_and_interval_to_sage(polyRangeCenterErrorSo):
197
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
198
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
199
    intervalSa = \
200
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
201
    centerSa = \
202
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
203
    errorSa = \
204
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
205
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
206
    # End slz_polynomial_and_interval_to_sage
207

    
208
print "sageSLZ loaded..."