Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (17,16 ko)

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

    
62
def slz_compute_scaled_function(functionSa, \
63
                                      lowerBoundSa, \
64
                                      upperBoundSa, \
65
                                      floatingPointPrecSa):
66
    """
67
    From a function, compute the scaled function whose domain
68
    is included in [1, 2) and whose image is also included in [1,2).
69
    Return a tuple: 
70
    [0]: the scaled function
71
    [1]: the scaled domain lower bound
72
    [2]: the scaled domain upper bound
73
    [3]: the scaled image lower bound
74
    [4]: the scaled image upper bound
75
    """
76
    x = functionSa.variables()[0]
77
    # Reassert f as a function (an not a mere expression).
78
    
79
    # Scalling the domain -> [1,2[.
80
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
81
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
82
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
83
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
84
    print "domainScalingExpression for argument :", domainScalingExpressionSa
85
    print "f: ", f
86
    ff = f.subs({x : domainScalingExpressionSa})
87
    #ff = f.subs_expr(x==domainScalingExpressionSa)
88
    domainScalingFunction(x) = invDomainScalingExpressionSa
89
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
90
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
91
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
92
    #
93
    # Scalling the image -> [1,2[.
94
    flbSa = f(lowerBoundSa).n()
95
    fubSa = f(upperBoundSa).n()
96
    if flbSa <= fubSa: # Increasing
97
        imageBinadeBottomSa = floor(flbSa.log2())
98
    else: # Decreasing
99
        imageBinadeBottomSa = floor(fubSa.log2())
100
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
101
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
102
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
103
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
104
    iis = invImageScalingExpressionSa.function(x)
105
    fff = iis.subs({x:ff})
106
    print "fff:", fff,
107
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
108
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
109
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
110

    
111
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
112
    # Create a polynomial over the rationals.
113
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
114
    return(polynomialRing(polyOfFloat))
115
# End slz_float_poly_of_float_to_rat_poly_of_rat
116

    
117
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
118
                                      lowerBoundSa, 
119
                                      upperBoundSa, floatingPointPrecSa, 
120
                                      internalSollyaPrecSa, approxPrecSa):
121
    """
122
    Under the assumption that:
123
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
124
    - lowerBound and upperBound belong to the same binade.
125
    from a:
126
    - function;
127
    - a degree
128
    - a pair of bounds;
129
    - the floating-point precision we work on;
130
    - the internal Sollya precision;
131
    - the requested approximation error
132
    The initial interval is, possibly, splitted into smaller intervals.
133
    It return a list of tuples, each made of:
134
    - a first polynomial (without the changed variable f(x) = p(x-x0));
135
    - a second polynomial (with a changed variable f(x) = q(x))
136
    - the approximation interval;
137
    - the center, x0, of the interval;
138
    - the corresponding approximation error.
139
    """
140
    x = functionSa.variables()[0] # Actual variable name can be anything.
141
    (fff, scaledLowerBoundSa, scaledUpperBoundSa, \
142
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) = \
143
                slz_compute_scaled_function(functionSa, \
144
                                            lowerBoundSa, \
145
                                            upperBoundSa, \
146
                                            floatingPointPrecSa)
147
    #
148
    resultArray = []
149
    #
150
    print "Approximation precision: ", RR(approxPrecSa)
151
    # Prepare the arguments for the Taylor expansion computation with Sollya.
152
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
153
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
154
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
155
                                                  scaledUpperBoundSa)
156
    # Compute the first Taylor expansion.
157
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
158
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
159
                                        scaledLowerBoundSa, scaledUpperBoundSa,
160
                                        approxPrecSa, internalSollyaPrecSa)
161
    # Change variable stuff
162
    changeVarExpressionSo = sollya_lib_build_function_sub(
163
                              sollya_lib_build_function_free_variable(), 
164
                              sollya_lib_copy_obj(intervalCenterSo))
165
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
166
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
167
                         maxErrorSo))
168
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
169
                                              upperBoundSa.parent().precision()))
170
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
171
    # Compute the next upper bound.
172
    # If the error of approximation is more than half of the target,
173
    # use the same interval.
174
    # If it is less, increase it a bit.
175
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
176
    currentErrorRatio = approxPrecSa / errorSa
177
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
178
    if currentErrorRatio  < 2 :
179
        currentScaledUpperBoundSa += \
180
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
181
    else:
182
        currentScaledUpperBoundSa += \
183
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
184
                         * currentErrorRatio.log2() * 2
185
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
186
        currentScaledUpperBoundSa = scaledUpperBoundSa
187
    # Compute the other expansions.
188
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
189
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
190
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
191
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
192
                                            currentScaledLowerBoundSa, 
193
                                            currentScaledUpperBoundSa, 
194
                                            approxPrecSa, 
195
                                            internalSollyaPrecSa)
196
        # Change variable stuff
197
        changeVarExpressionSo = sollya_lib_build_function_sub(
198
                                  sollya_lib_build_function_free_variable(), 
199
                                  sollya_lib_copy_obj(intervalCenterSo))
200
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
201
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
202
                            intervalCenterSo, maxErrorSo))
203
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
204
        # Compute the next upper bound.
205
        # If the error of approximation is more than half of the target,
206
        # use the same interval.
207
        # If it is less, increase it a bit.
208
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
209
        currentErrorRatio = approxPrecSa / errorSa
210
        if currentErrorRatio  < RR('1.5') :
211
            currentScaledUpperBoundSa = \
212
                            boundsSa.endpoints()[1] + \
213
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
214
        elif currentErrorRatio < 2:
215
            currentScaledUpperBoundSa = \
216
                            boundsSa.endpoints()[1] + \
217
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
218
                             * currentErrorRatio.log2()
219
        else:
220
            currentScaledUpperBoundSa = \
221
                            boundsSa.endpoints()[1] + \
222
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
223
                             * currentErrorRatio.log2() * 2
224
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
225
            currentScaledUpperBoundSa = scaledUpperBoundSa
226
    sollya_lib_clear_obj(functionSo)
227
    sollya_lib_clear_obj(degreeSo)
228
    sollya_lib_clear_obj(scaledBoundsSo)
229
    return(resultArray)
230
# End slz_get_intervals_and_polynomials
231

    
232

    
233
def slz_interval_scaling_expression(boundsInterval, expVar):
234
    """
235
    Compute the scaling expression to map an interval that span only
236
    a binade to [1, 2) and the inverse expression as well.
237
    Not very sure that the transformation makes sense for negative numbers.
238
    """
239
    # The scaling offset is only used for negative numbers.
240
    if abs(boundsInterval.endpoints()[0]) < 1:
241
        if boundsInterval.endpoints()[0] >= 0:
242
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
243
            invScalingCoeff = 1/scalingCoeff
244
            return((scalingCoeff * expVar, 
245
                    invScalingCoeff * expVar))
246
        else:
247
            scalingCoeff = \
248
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
249
            scalingOffset = -3 * scalingCoeff
250
            return((scalingCoeff * expVar + scalingOffset,
251
                    1/scalingCoeff * expVar + 3))
252
    else: 
253
        if boundsInterval.endpoints()[0] >= 0:
254
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
255
            scalingOffset = 0
256
            return((scalingCoeff * expVar, 
257
                    1/scalingCoeff * expVar))
258
        else:
259
            scalingCoeff = \
260
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
261
            scalingOffset =  -3 * scalingCoeff
262
            #scalingOffset = 0
263
            return((scalingCoeff * expVar + scalingOffset,
264
                    1/scalingCoeff * expVar + 3))
265

    
266
   
267
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
268
    """
269
    Compute the Sage version of the Taylor polynomial and it's
270
    companion data (interval, center...)
271
    The input parameter is a five elements tuple:
272
    - [0]: the polyomial (without variable change), as polynomial over a
273
           real ring;
274
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
275
           over a real ring;
276
    - [2]: the interval (as Sollya range);
277
    - [3]: the interval center;
278
    - [4]: the approximation error. 
279
    
280
    The function return a 5 elements tuple: formed with all the 
281
    input elements converted into their Sollya counterpart.
282
    """
283
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
284
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
285
    intervalSa = \
286
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
287
    centerSa = \
288
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
289
    errorSa = \
290
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
291
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
292
    # End slz_interval_and_polynomial_to_sage
293

    
294
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
295
                                                precision,
296
                                                targetHardnessToRound,
297
                                                variable1,
298
                                                variable2):
299
    """
300
    Creates a new polynomial with integer coefficients for use with the
301
    Coppersmith method.
302
    A the same time it computes :
303
    - 2^K (N);
304
    - 2^k
305
    - lcm
306
    """
307
    # Create a new integer polynomial ring.
308
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
309
    # Coefficients are issued in the increasing power order.
310
    ratPolyCoefficients = ratPolyOfInt.coefficients()
311
    # Build the list of number we compute the lcmm of.
312
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
313
    coefficientDenominators.append(2^precision)
314
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
315
    leastCommonMultiple = sro_lcmm(coefficientDenominators)
316
    # Compute the lcm
317
    leastCommonMultiple = sro_lcmm(coefficientDenominators)
318
    # Compute the expression corresponding to the new polynomial
319
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
320
    print coefficientNumerators
321
    polynomialExpression = 0
322
    power = 0
323
    # Iterate over two lists at the same time, stop when the shorter is
324
    # exhausted.
325
    for numerator, denominator in \
326
                            zip(coefficientNumerators, coefficientDenominators):
327
        multiplicator = leastCommonMultiple / denominator 
328
        newCoefficient = numerator * multiplicator
329
        polynomialExpression += newCoefficient * variable1^power
330
        power +=1
331
    polynomialExpression += - variable2
332
    return (IP(polynomialExpression),
333
            leastCommonMultiple / 2^precision, # 2^K or N.
334
            leastCommonMultiple / 2 ^(targetHardnessToRound + 1), # tBound
335
            leastCommonMultiple)
336
        
337
# End slz_ratPoly_of_int_to_poly_for_coppersmith
338

    
339
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
340
                                          precision):
341
    """
342
    Makes a variable substitution into the input polynomial so that the output
343
    polynomial can take integer arguments.
344
    All variables of the input polynomial "have precision p". That is to say
345
    that they are rationals with denominator == 2^precision: x = y/2^precision
346
    We "incorporate" these denominators into the coefficients with, 
347
    respectively, the "right" power.
348
    """
349
    polynomialField = ratPolyOfRat.parent()
350
    polynomialVariable = rationalPolynomial.variables()[0]
351
    print "The polynomial field is:", polynomialField
352
    return \
353
        polynomialField(rationalPolynomial.subs({polynomialVariable : \
354
                                   polynomialVariable/2^(precision-1)}))
355
    
356
    # Return a tuple:
357
    # - the bivariate integer polynomial in (i,j);
358
    # - 2^K
359
# End slz_rat_poly_of_rat_to_rat_poly_of_int
360

    
361
print "sageSLZ loaded..."