Statistiques
| Révision :

root / pobysoPythonSage / src / sageSLZ.sage @ 66

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

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