Statistiques
| Révision :

root / pobysoPythonSage / src / sageSLZ.sage @ 61

Historique | Voir | Annoter | Télécharger (8,67 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 + (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, degreeSa, lowerBoundSa, 
60
                                      upperBoundSa, floatingPointPrecSa, 
61
                                      internalSollyaPrecSa):
62
    """
63
    Under the assumption that:
64
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
65
    - lowerBound and upperBound belong to the same binade.
66
    from a:
67
    - function;
68
    - a degree
69
    - a pair of bounds;
70
    - the floating-point precision we work on;
71
    - the internal Sollya precision;
72
    compute a list of tuples made of:
73
    - a polynomial approximating the function (a Sollya object);
74
    - the range for which the polynomial approximates the function 
75
      (a Sollya object);
76
    - the center of the interval (a Sollya object);
77
    - the approximation error (a Sage object). 
78
      with the error given as the last element (a Sage object);
79
    The initial interval is, possibly, splitted into smaller intervals.
80
    It return a list of tuples, each made of:
81
    - a polynomial;
82
    - the approximation interval;
83
    - the center, x0,  of the interval (the polynomial is defined as p(x-x0));
84
    - the corresponding approximation error.
85
    """
86
    # Scalling the domain -> [1,2[.
87
    # Notice the clumsy notation for log2.
88
    domainScalingFactorSa = floor(lowerBound.log2()) + 1
89
    print "domainScalingFactor for argument :", domainScalingFactorSa.n()
90
    ff(x) = f(x * domainScalingFactorSa)
91
    scaledLowerBoundSa = lowerBoundSa/domainScalingFactorSa
92
    scaledUpperBoundSa = upperBoundSa/domainScalingFactorSa
93
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
94
    #
95
    # Scalling the image -> [1,2[.
96
    flb = f(lowerBoundSa).n()
97
    fub = f(upperBoundSa).n()
98
    if flb <= fub: # Increasing
99
        imageBinadeBottom = floor(flb.log2())
100
    else: # Decreasing
101
        imageBinadeBottom = floor(fub.log2())
102
    print 'ff:', ff, '- Image:', flb, fub, imageBinadeBottom
103
    #
104
    resultArray = []
105
    #
106
    approxPrecSa = 1/(2^(floatingPointPrecSa + 1))
107
    print "Approximation precision: ", RR(approxPrecSa)
108
    # Prepare the arguments for the Taylor expansion computation with Sollya.
109
    functionSo = pobyso_parse_string_sa_so(functionSa._assume_str())
110
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
111
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
112
                                                  scaledUpperBoundSa)
113
    absoluteErrorTypeSo = pobyso_absolute_so_so()
114
    # Compute the first Taylor expansion.
115
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
116
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
117
                                        scaledLowerBoundSa, scaledUpperBoundSa,
118
                                        approxPrecSa, internalSollyaPrecSa)
119
    resultArray.append((polySo, boundsSo, intervalCenterSo, maxErrorSo))
120
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
121
                                              upperBoundSa.parent().precision()))
122
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
123
    # Compute the other expansions.
124
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
125
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
126
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
127
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
128
                                            currentScaledLowerBoundSa, 
129
                                            scaledUpperBoundSa, approxPrecSa, 
130
                                            internalSollyaPrecSa)
131
        resultArray.append((polySo, boundsSo, intervalCenterSo, maxErrorSo))
132
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
133
    sollya_lib_clear_obj(functionSo)
134
    sollya_lib_clear_obj(degreeSo)
135
    sollya_lib_clear_obj(scaledBoundsSo)
136
    sollya_lib_clear_obj(absoluteErrorTypeSo)
137
    return(resultArray)
138
    # End slz_get_intervals_and_polynomials
139

    
140
def slz_interval_scaling_expression(boundsInterval, varName):
141
    """
142
    Compute the scaling expression to map an interval that span only
143
    a binade to [1, 2)
144
    """
145
    if abs(boundsInterval.endpoints()[0]) < 1:
146
        if boundsInterval.endpoints()[0] >= 0:
147
            scalingCoeff = 2^(-floor(boundsInterval.endpoints()[0].log2()))
148
            return(scalingCoeff * eval(varName))
149
        else:
150
            scalingCoeff = 2^(-floor((-boundsInterval.endpoints()[1]).log2()))
151
            scalingOffset = -ceil(scalingCoeff * boundsInterval.endpoints()[0])
152
            return(scalingCoeff * eval(varName) + scalingOffset)
153
    else: 
154
        if boundsInterval.endpoints()[0] >= 0:
155
            scalingCoeff = 2^(-floor(boundsInterval.endpoints()[0].log2()))
156
            scalingOffset = 0
157
            return(scalingCoeff * eval(varName))
158
        else:
159
            scalingCoeff = 2^(-floor((-boundsInterval.endpoints()[1]).log2()))
160
            scalingOffset = floor(-(scalingCoeff * boundsInterval.endpoints()[1]) + 2)
161
            return(scalingCoeff * eval(varName) + scalingOffset)
162

    
163
   
164
def slz_polynomial_and_interval_to_sage(polyRangeCenterErrorSo):
165
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
166
    intervalSa = \
167
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[1])
168
    centerSa = \
169
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[2])
170
    errorSa = \
171
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
172
    return((polynomialSa, intervalSa, centerSa, errorSa))
173
    # End slz_polynomial_and_interval_to_sage