Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (18,58 ko)

1
print "sageSLZ loading..."
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
    intervalShrinkConstFactorSa = RRR('0.5')
17
    absoluteErrorTypeSo = pobyso_absolute_so_so()
18
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
19
    currentUpperBoundSa = upperBoundSa
20
    currentLowerBoundSa = lowerBoundSa
21
    # What we want here is the polynomial without the variable change, 
22
    # since our actual variable will be x-intervalCenter defined over the 
23
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter]. 
24
    (polySo, intervalCenterSo, maxErrorSo) = \
25
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
26
                                                    currentRangeSo, 
27
                                                    absoluteErrorTypeSo)
28
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
29
    while maxErrorSa > approxPrecSa:
30
        sollya_lib_clear_obj(maxErrorSo)
31
        sollya_lib_clear_obj(polySo)
32
        sollya_lib_clear_obj(intervalCenterSo)
33
        shrinkFactorSa = RRR('5.0')/(maxErrorSa/approxPrecSa).log2().abs()
34
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
35
        #errorRatioSa = approxPrecSa/maxErrorSa
36
        #print "Error ratio: ", errorRatioSa
37
        
38
        if shrinkFactorSa > intervalShrinkConstFactorSa:
39
            actualShrinkFactorSa = intervalShrinkConstFactorSa
40
            #print "Fixed"
41
        else:
42
            actualShrinkFactorSa = shrinkFactorSa
43
            #print "Computed",shrinkFactorSa,maxErrorSa
44
            #print shrinkFactorSa, maxErrorSa
45
        currentUpperBoundSa = currentLowerBoundSa + \
46
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
47
                                   actualShrinkFactorSa
48
        #print "Current upper bound:", currentUpperBoundSa
49
        sollya_lib_clear_obj(currentRangeSo)
50
        sollya_lib_clear_obj(polySo)
51
        if currentUpperBoundSa <= currentLowerBoundSa:
52
            sollya_lib_clear_obj(absoluteErrorTypeSo)
53
            print "Can't find an interval."
54
            print "Use either or both a higher polynomial degree or a higher",
55
            print "internal precision."
56
            print "Aborting!"
57
            return (None, None, None, None)
58
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa, 
59
                                                      currentUpperBoundSa)
60
        # print "New interval:",
61
        # pobyso_autoprint(currentRangeSo)
62
        (polySo, intervalCenterSo, maxErrorSo) = \
63
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo, 
64
                                                        currentRangeSo, 
65
                                                        absoluteErrorTypeSo)
66
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
67
        #print "Max errorSo:",
68
        #pobyso_autoprint(maxErrorSo)
69
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
70
        #print "Max errorSa:", maxErrorSa
71
        #print "Sollya prec:",
72
        #pobyso_autoprint(sollya_lib_get_prec(None))
73
    sollya_lib_clear_obj(absoluteErrorTypeSo)
74
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
75
# End slz_compute_polynomial_and_interval
76

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

    
126
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
127
    # Create a polynomial over the rationals.
128
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
129
    return(polynomialRing(polyOfFloat))
130
# End slz_float_poly_of_float_to_rat_poly_of_rat.
131

    
132
def slz_get_intervals_and_polynomials(functionSa, degreeSa, 
133
                                      lowerBoundSa, 
134
                                      upperBoundSa, floatingPointPrecSa, 
135
                                      internalSollyaPrecSa, approxPrecSa):
136
    """
137
    Under the assumption that:
138
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
139
    - lowerBound and upperBound belong to the same binade.
140
    from a:
141
    - function;
142
    - a degree
143
    - a pair of bounds;
144
    - the floating-point precision we work on;
145
    - the internal Sollya precision;
146
    - the requested approximation error
147
    The initial interval is, possibly, splitted into smaller intervals.
148
    It return a list of tuples, each made of:
149
    - a first polynomial (without the changed variable f(x) = p(x-x0));
150
    - a second polynomial (with a changed variable f(x) = q(x))
151
    - the approximation interval;
152
    - the center, x0, of the interval;
153
    - the corresponding approximation error.
154
    """
155
    currentSollyaPrecSo = pobyso_get_prec_so()
156
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
157
    if internalSollyaPrecSa > currentSollyaPrecSa:
158
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
159
    x = functionSa.variables()[0] # Actual variable name can be anything.
160
    (fff, scaledLowerBoundSa, scaledUpperBoundSa, \
161
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) = \
162
                slz_compute_scaled_function(functionSa, \
163
                                            lowerBoundSa, \
164
                                            upperBoundSa, \
165
                                            floatingPointPrecSa)
166
    #
167
    resultArray = []
168
    #
169
    print "Approximation precision: ", RR(approxPrecSa)
170
    # Prepare the arguments for the Taylor expansion computation with Sollya.
171
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
172
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
173
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa, 
174
                                                  scaledUpperBoundSa)
175
    # Compute the first Taylor expansion.
176
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
177
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
178
                                        scaledLowerBoundSa, scaledUpperBoundSa,
179
                                        approxPrecSa, internalSollyaPrecSa)
180
    if polySo is None:
181
        print "Aborting"
182
        return None
183
    # Change variable stuff
184
    changeVarExpressionSo = sollya_lib_build_function_sub(
185
                              sollya_lib_build_function_free_variable(), 
186
                              sollya_lib_copy_obj(intervalCenterSo))
187
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
188
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
189
                         maxErrorSo))
190
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
191
                                              upperBoundSa.parent().precision()))
192
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
193
    # Compute the next upper bound.
194
    # If the error of approximation is more than half of the target,
195
    # use the same interval.
196
    # If it is less, increase it a bit.
197
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
198
    currentErrorRatio = approxPrecSa / errorSa
199
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
200
    if currentErrorRatio  < 2 :
201
        currentScaledUpperBoundSa += \
202
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
203
    else:
204
        currentScaledUpperBoundSa += \
205
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
206
                         * currentErrorRatio.log2() * 2
207
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
208
        currentScaledUpperBoundSa = scaledUpperBoundSa
209
    # Compute the other expansions.
210
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
211
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
212
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
213
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
214
                                            currentScaledLowerBoundSa, 
215
                                            currentScaledUpperBoundSa, 
216
                                            approxPrecSa, 
217
                                            internalSollyaPrecSa)
218
        # Change variable stuff
219
        changeVarExpressionSo = sollya_lib_build_function_sub(
220
                                  sollya_lib_build_function_free_variable(), 
221
                                  sollya_lib_copy_obj(intervalCenterSo))
222
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo) 
223
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
224
                            intervalCenterSo, maxErrorSo))
225
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
226
        # Compute the next upper bound.
227
        # If the error of approximation is more than half of the target,
228
        # use the same interval.
229
        # If it is less, increase it a bit.
230
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
231
        currentErrorRatio = approxPrecSa / errorSa
232
        if currentErrorRatio  < RR('1.5') :
233
            currentScaledUpperBoundSa = \
234
                            boundsSa.endpoints()[1] + \
235
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
236
        elif currentErrorRatio < 2:
237
            currentScaledUpperBoundSa = \
238
                            boundsSa.endpoints()[1] + \
239
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
240
                             * currentErrorRatio.log2()
241
        else:
242
            currentScaledUpperBoundSa = \
243
                            boundsSa.endpoints()[1] + \
244
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
245
                             * currentErrorRatio.log2() * 2
246
        # Test for insufficient precision.
247
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
248
            print "Can't shrink the interval anymore!"
249
            print "You should consider increasing the Sollya internal precision"
250
            print "or the polynomial degree."
251
            print "Giving up!"
252
            sollya_lib_clear_obj(functionSo)
253
            sollya_lib_clear_obj(degreeSo)
254
            sollya_lib_clear_obj(scaledBoundsSo)
255
            return None
256
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
257
            currentScaledUpperBoundSa = scaledUpperBoundSa
258
    sollya_lib_clear_obj(functionSo)
259
    sollya_lib_clear_obj(degreeSo)
260
    sollya_lib_clear_obj(scaledBoundsSo)
261
    if internalSollyaPrecSa > currentSollyaPrecSa:
262
        pobyso_set_prec_so_so(currentSollyaPrecSo)
263
    return(resultArray)
264
# End slz_get_intervals_and_polynomials
265

    
266

    
267
def slz_interval_scaling_expression(boundsInterval, expVar):
268
    """
269
    Compute the scaling expression to map an interval that span only
270
    a binade to [1, 2) and the inverse expression as well.
271
    Not very sure that the transformation makes sense for negative numbers.
272
    """
273
    # The scaling offset is only used for negative numbers.
274
    if abs(boundsInterval.endpoints()[0]) < 1:
275
        if boundsInterval.endpoints()[0] >= 0:
276
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
277
            invScalingCoeff = 1/scalingCoeff
278
            return((scalingCoeff * expVar, 
279
                    invScalingCoeff * expVar))
280
        else:
281
            scalingCoeff = \
282
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
283
            scalingOffset = -3 * scalingCoeff
284
            return((scalingCoeff * expVar + scalingOffset,
285
                    1/scalingCoeff * expVar + 3))
286
    else: 
287
        if boundsInterval.endpoints()[0] >= 0:
288
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
289
            scalingOffset = 0
290
            return((scalingCoeff * expVar, 
291
                    1/scalingCoeff * expVar))
292
        else:
293
            scalingCoeff = \
294
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
295
            scalingOffset =  -3 * scalingCoeff
296
            #scalingOffset = 0
297
            return((scalingCoeff * expVar + scalingOffset,
298
                    1/scalingCoeff * expVar + 3))
299

    
300
   
301
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
302
    """
303
    Compute the Sage version of the Taylor polynomial and it's
304
    companion data (interval, center...)
305
    The input parameter is a five elements tuple:
306
    - [0]: the polyomial (without variable change), as polynomial over a
307
           real ring;
308
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
309
           over a real ring;
310
    - [2]: the interval (as Sollya range);
311
    - [3]: the interval center;
312
    - [4]: the approximation error. 
313
    
314
    The function return a 5 elements tuple: formed with all the 
315
    input elements converted into their Sollya counterpart.
316
    """
317
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
318
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
319
    intervalSa = \
320
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
321
    centerSa = \
322
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
323
    errorSa = \
324
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
325
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
326
    # End slz_interval_and_polynomial_to_sage
327

    
328
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt, 
329
                                                precision,
330
                                                targetHardnessToRound,
331
                                                variable1,
332
                                                variable2):
333
    """
334
    Creates a new polynomial with integer coefficients for use with the
335
    Coppersmith method.
336
    A the same time it computes :
337
    - 2^K (N);
338
    - 2^k
339
    - lcm
340
    """
341
    # Create a new integer polynomial ring.
342
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
343
    # Coefficients are issued in the increasing power order.
344
    ratPolyCoefficients = ratPolyOfInt.coefficients()
345
    # Build the list of number we compute the lcmm of.
346
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
347
    coefficientDenominators.append(2^precision)
348
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
349
    # Compute the lcm
350
    leastCommonMultiple = lcm(coefficientDenominators)
351
    # Compute the expression corresponding to the new polynomial
352
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
353
    print coefficientNumerators
354
    polynomialExpression = 0
355
    power = 0
356
    # Iterate over two lists at the same time, stop when the shorter is
357
    # exhausted.
358
    for numerator, denominator in \
359
                            zip(coefficientNumerators, coefficientDenominators):
360
        multiplicator = leastCommonMultiple / denominator 
361
        newCoefficient = numerator * multiplicator
362
        polynomialExpression += newCoefficient * variable1^power
363
        power +=1
364
    polynomialExpression += - variable2
365
    return (IP(polynomialExpression),
366
            leastCommonMultiple / 2^precision, # 2^K or N.
367
            leastCommonMultiple / 2 ^(targetHardnessToRound + 1), # tBound
368
            leastCommonMultiple)
369
        
370
# End slz_ratPoly_of_int_to_poly_for_coppersmith
371

    
372
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat, 
373
                                          precision):
374
    """
375
    Makes a variable substitution into the input polynomial so that the output
376
    polynomial can take integer arguments.
377
    All variables of the input polynomial "have precision p". That is to say
378
    that they are rationals with denominator == 2^precision: x = y/2^precision
379
    We "incorporate" these denominators into the coefficients with, 
380
    respectively, the "right" power.
381
    """
382
    polynomialField = ratPolyOfRat.parent()
383
    polynomialVariable = rationalPolynomial.variables()[0]
384
    print "The polynomial field is:", polynomialField
385
    return \
386
        polynomialField(rationalPolynomial.subs({polynomialVariable : \
387
                                   polynomialVariable/2^(precision-1)}))
388
    
389
    # Return a tuple:
390
    # - the bivariate integer polynomial in (i,j);
391
    # - 2^K
392
# End slz_rat_poly_of_rat_to_rat_poly_of_int
393

    
394
print "\t...sageSLZ loaded"