Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (13,07 ko)

1 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
2 61 storres
                                        upperBoundSa, approxPrecSa,
3 61 storres
                                        sollyaPrecSa=None):
4 61 storres
    """
5 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
6 61 storres
    a polynomial that approximates the function on a an interval starting
7 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
8 61 storres
    approximates with the expected precision.
9 61 storres
    The interval upper bound is lowered until the expected approximation
10 61 storres
    precision is reached.
11 61 storres
    The polynomial, the bounds, the center of the interval and the error
12 61 storres
    are returned.
13 61 storres
    """
14 61 storres
    RRR = lowerBoundSa.parent()
15 61 storres
    #goldenRatioSa = RRR(5.sqrt() / 2 - 1/2)
16 61 storres
    #intervalShrinkConstFactorSa = goldenRatioSa
17 61 storres
    intervalShrinkConstFactorSa = RRR('0.5')
18 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
19 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
20 61 storres
    currentUpperBoundSa = upperBoundSa
21 61 storres
    currentLowerBoundSa = lowerBoundSa
22 61 storres
    # What we want here is the polynomial without the variable change,
23 61 storres
    # since our actual variable will be x-intervalCenter defined over the
24 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
25 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
26 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
27 61 storres
                                                    currentRangeSo,
28 61 storres
                                                    absoluteErrorTypeSo)
29 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
30 61 storres
    while maxErrorSa > approxPrecSa:
31 61 storres
        sollya_lib_clear_obj(maxErrorSo)
32 71 storres
        errorRatioSa = 1/(maxErrorSa/approxPrecSa).log2()
33 61 storres
        #print "Error ratio: ", errorRatioSa
34 71 storres
        if errorRatioSa > intervalShrinkConstFactorSa:
35 61 storres
            currentUpperBoundSa = currentLowerBoundSa + \
36 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
37 61 storres
                                   intervalShrinkConstFactorSa
38 61 storres
        else:
39 61 storres
            currentUpperBoundSa = currentLowerBoundSa + \
40 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
41 61 storres
                                  intervalShrinkConstFactorSa
42 71 storres
            currentUpperBoundSa = currentLowerBoundSa + \
43 71 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
44 71 storres
                                  errorRatioSa
45 71 storres
        #print "Current upper bound:", currentUpperBoundSa
46 61 storres
        sollya_lib_clear_obj(currentRangeSo)
47 61 storres
        sollya_lib_clear_obj(polySo)
48 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
49 61 storres
                                                      currentUpperBoundSa)
50 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
51 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
52 61 storres
                                                        currentRangeSo,
53 61 storres
                                                        absoluteErrorTypeSo)
54 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
55 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
56 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
57 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
58 61 storres
    # End slz_compute_polynomial_and_interval
59 61 storres
60 72 storres
def slz_compute_scaled_function(functionSa, \
61 72 storres
                                      variableNameSa, \
62 72 storres
                                      lowerBoundSa, \
63 72 storres
                                      upperBoundSa, \
64 72 storres
                                      floatingPointPrecSa):
65 72 storres
    """
66 72 storres
    From a function, compute the scaled function whose domain
67 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
68 72 storres
    Return a tuple:
69 72 storres
    [0]: the scaled function
70 72 storres
    [1]: the scaled domain lower bound
71 72 storres
    [2]: the scaled domain upper bound
72 72 storres
    [3]: the scaled image lower bound
73 72 storres
    [4]: the scaled image upper bound
74 72 storres
    """
75 72 storres
    x = var(variableNameSa)
76 72 storres
    # Scalling the domain -> [1,2[.
77 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
78 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
79 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
80 72 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, variableNameSa)
81 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
82 72 storres
    print "f: ", f
83 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
84 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
85 72 storres
    scaledLowerBoundSa = invDomainScalingExpressionSa(lowerBoundSa).n()
86 72 storres
    scaledUpperBoundSa = invDomainScalingExpressionSa(upperBoundSa).n()
87 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
88 72 storres
    #
89 72 storres
    # Scalling the image -> [1,2[.
90 72 storres
    flbSa = f(lowerBoundSa).n()
91 72 storres
    fubSa = f(upperBoundSa).n()
92 72 storres
    if flbSa <= fubSa: # Increasing
93 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
94 72 storres
    else: # Decreasing
95 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
96 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
97 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
98 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
99 72 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, variableNameSa)
100 72 storres
    iis = invImageScalingExpressionSa.function(x)
101 72 storres
    fff = iis.subs({x:ff})
102 72 storres
    print "fff:", fff,
103 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
104 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
105 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
106 72 storres
107 63 storres
def slz_get_intervals_and_polynomials(functionSa, variableNameSa, degreeSa,
108 63 storres
                                      lowerBoundSa,
109 60 storres
                                      upperBoundSa, floatingPointPrecSa,
110 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
111 60 storres
    """
112 60 storres
    Under the assumption that:
113 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
114 60 storres
    - lowerBound and upperBound belong to the same binade.
115 60 storres
    from a:
116 60 storres
    - function;
117 60 storres
    - a degree
118 60 storres
    - a pair of bounds;
119 60 storres
    - the floating-point precision we work on;
120 60 storres
    - the internal Sollya precision;
121 64 storres
    - the requested approximation error
122 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
123 61 storres
    It return a list of tuples, each made of:
124 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
125 72 storres
    - a second polynomila (with a changed variable f(x) = q(x))
126 61 storres
    - the approximation interval;
127 72 storres
    - the center, x0, of the interval;
128 61 storres
    - the corresponding approximation error.
129 60 storres
    """
130 63 storres
    x = var(variableNameSa)
131 60 storres
    # Scalling the domain -> [1,2[.
132 62 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
133 62 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
134 62 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
135 63 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, variableNameSa)
136 62 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
137 63 storres
    print "f: ", f
138 64 storres
    ff = f.subs({x : domainScalingExpressionSa})
139 64 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
140 62 storres
    scaledLowerBoundSa = invDomainScalingExpressionSa(lowerBoundSa).n()
141 62 storres
    scaledUpperBoundSa = invDomainScalingExpressionSa(upperBoundSa).n()
142 60 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
143 60 storres
    #
144 60 storres
    # Scalling the image -> [1,2[.
145 62 storres
    flbSa = f(lowerBoundSa).n()
146 62 storres
    fubSa = f(upperBoundSa).n()
147 62 storres
    if flbSa <= fubSa: # Increasing
148 62 storres
        imageBinadeBottomSa = floor(flbSa.log2())
149 60 storres
    else: # Decreasing
150 62 storres
        imageBinadeBottomSa = floor(fubSa.log2())
151 62 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
152 62 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
153 62 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
154 63 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, variableNameSa)
155 63 storres
    iis = invImageScalingExpressionSa.function(x)
156 63 storres
    fff = iis.subs({x:ff})
157 62 storres
    print "fff:", fff,
158 62 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
159 60 storres
    #
160 60 storres
    resultArray = []
161 60 storres
    #
162 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
163 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
164 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
165 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
166 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
167 61 storres
                                                  scaledUpperBoundSa)
168 61 storres
    # Compute the first Taylor expansion.
169 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
170 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
171 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
172 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
173 64 storres
    # Change variable stuff
174 62 storres
    changeVarExpressionSo = sollya_lib_build_function_sub(
175 62 storres
                              sollya_lib_build_function_free_variable(),
176 62 storres
                              sollya_lib_copy_obj(intervalCenterSo))
177 62 storres
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
178 64 storres
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
179 64 storres
                         maxErrorSo))
180 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
181 60 storres
                                              upperBoundSa.parent().precision()))
182 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
183 61 storres
    # Compute the other expansions.
184 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
185 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
186 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
187 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
188 60 storres
                                            currentScaledLowerBoundSa,
189 60 storres
                                            scaledUpperBoundSa, approxPrecSa,
190 60 storres
                                            internalSollyaPrecSa)
191 64 storres
        # Change variable stuff
192 64 storres
        changeVarExpressionSo = sollya_lib_build_function_sub(
193 64 storres
                                  sollya_lib_build_function_free_variable(),
194 64 storres
                                  sollya_lib_copy_obj(intervalCenterSo))
195 64 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
196 64 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
197 64 storres
                            intervalCenterSo, maxErrorSo))
198 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
199 60 storres
    sollya_lib_clear_obj(functionSo)
200 60 storres
    sollya_lib_clear_obj(degreeSo)
201 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
202 60 storres
    return(resultArray)
203 60 storres
    # End slz_get_intervals_and_polynomials
204 60 storres
205 61 storres
def slz_interval_scaling_expression(boundsInterval, varName):
206 61 storres
    """
207 61 storres
    Compute the scaling expression to map an interval that span only
208 62 storres
    a binade to [1, 2) and the inverse expression as well.
209 62 storres
    Not very sure that the transformation makes sense for negative numbers.
210 61 storres
    """
211 62 storres
    # The scaling offset is only used for negative numbers.
212 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
213 61 storres
        if boundsInterval.endpoints()[0] >= 0:
214 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
215 62 storres
            invScalingCoeff = 1/scalingCoeff
216 62 storres
            return((scalingCoeff * eval(varName),
217 62 storres
                    invScalingCoeff * eval(varName)))
218 60 storres
        else:
219 62 storres
            scalingCoeff = \
220 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
221 62 storres
            scalingOffset = -3 * scalingCoeff
222 62 storres
            return((scalingCoeff * eval(varName) + scalingOffset,
223 62 storres
                    1/scalingCoeff * eval(varName) + 3))
224 61 storres
    else:
225 61 storres
        if boundsInterval.endpoints()[0] >= 0:
226 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
227 61 storres
            scalingOffset = 0
228 62 storres
            return((scalingCoeff * eval(varName),
229 62 storres
                    1/scalingCoeff * eval(varName)))
230 61 storres
        else:
231 62 storres
            scalingCoeff = \
232 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
233 62 storres
            scalingOffset =  -3 * scalingCoeff
234 62 storres
            #scalingOffset = 0
235 62 storres
            return((scalingCoeff * eval(varName) + scalingOffset,
236 62 storres
                    1/scalingCoeff * eval(varName) + 3))
237 61 storres
238 61 storres
239 60 storres
def slz_polynomial_and_interval_to_sage(polyRangeCenterErrorSo):
240 72 storres
    """
241 72 storres
    Compute the Sage version of the Taylor polynomial and it's
242 72 storres
    companion data (interval, center...)
243 72 storres
    The input parameter is a five elements tuple:
244 72 storres
    - [0]: the polyomial (without variable change);
245 72 storres
    - [1]: the polyomial (with variable change done in Sollya);
246 72 storres
    - [2]: the interval (as Sollya range);
247 72 storres
    - [3]: the interval center;
248 72 storres
    - [4]: the approximation error.
249 72 storres
250 72 storres
    The function return a 5 elements tuple: formed with all the
251 72 storres
    input elements converted into their Sollya counterpart.
252 72 storres
    """
253 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
254 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
255 60 storres
    intervalSa = \
256 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
257 60 storres
    centerSa = \
258 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
259 60 storres
    errorSa = \
260 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
261 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
262 60 storres
    # End slz_polynomial_and_interval_to_sage
263 62 storres
264 62 storres
print "sageSLZ loaded..."