Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (10,61 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 = 1/(maxErrorSa/approxPrecSa).log2()
34
        #print "Error ratio: ", errorRatioSa
35
        if errorRatioSa > intervalShrinkConstFactorSa:
36
            currentUpperBoundSa = currentLowerBoundSa + \
37
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
38
                                   intervalShrinkConstFactorSa
39
        else:
40
            currentUpperBoundSa = currentLowerBoundSa + \
41
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
42
                                  intervalShrinkConstFactorSa
43
            currentUpperBoundSa = currentLowerBoundSa + \
44
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
45
                                  errorRatioSa
46
        #print "Current upper bound:", currentUpperBoundSa
47
        sollya_lib_clear_obj(currentRangeSo)
48
        sollya_lib_clear_obj(polySo)
49
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
50
                                                      currentUpperBoundSa)
51
        (polySo, intervalCenterSo, maxErrorSo) = \
52
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
53
                                                        currentRangeSo, 
54
                                                        absoluteErrorTypeSo)
55
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
56
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
57
    sollya_lib_clear_obj(absoluteErrorTypeSo)
58
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
59
    # End slz_compute_polynomial_and_interval
60

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

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

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

    
210
print "sageSLZ loaded..."