Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (17,16 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
    intervalShrinkConstFactorSa = RRR('0.5')
16 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
17 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
18 61 storres
    currentUpperBoundSa = upperBoundSa
19 61 storres
    currentLowerBoundSa = lowerBoundSa
20 61 storres
    # What we want here is the polynomial without the variable change,
21 61 storres
    # since our actual variable will be x-intervalCenter defined over the
22 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
23 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
24 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
25 61 storres
                                                    currentRangeSo,
26 61 storres
                                                    absoluteErrorTypeSo)
27 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
28 61 storres
    while maxErrorSa > approxPrecSa:
29 61 storres
        sollya_lib_clear_obj(maxErrorSo)
30 81 storres
        sollya_lib_clear_obj(polySo)
31 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
32 81 storres
        shrinkFactorSa = RRR('5.0')/(maxErrorSa/approxPrecSa).log2().abs()
33 81 storres
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
34 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
35 61 storres
        #print "Error ratio: ", errorRatioSa
36 81 storres
37 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
38 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
39 81 storres
            #print "Fixed"
40 61 storres
        else:
41 81 storres
            actualShrinkFactorSa = shrinkFactorSa
42 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
43 81 storres
            #print shrinkFactorSa, maxErrorSa
44 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
45 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
46 81 storres
                                   actualShrinkFactorSa
47 71 storres
        #print "Current upper bound:", currentUpperBoundSa
48 61 storres
        sollya_lib_clear_obj(currentRangeSo)
49 61 storres
        sollya_lib_clear_obj(polySo)
50 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
51 61 storres
                                                      currentUpperBoundSa)
52 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
53 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
54 61 storres
                                                        currentRangeSo,
55 61 storres
                                                        absoluteErrorTypeSo)
56 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
57 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
58 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
59 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
60 81 storres
# End slz_compute_polynomial_and_interval
61 61 storres
62 72 storres
def slz_compute_scaled_function(functionSa, \
63 72 storres
                                      lowerBoundSa, \
64 72 storres
                                      upperBoundSa, \
65 72 storres
                                      floatingPointPrecSa):
66 72 storres
    """
67 72 storres
    From a function, compute the scaled function whose domain
68 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
69 72 storres
    Return a tuple:
70 72 storres
    [0]: the scaled function
71 72 storres
    [1]: the scaled domain lower bound
72 72 storres
    [2]: the scaled domain upper bound
73 72 storres
    [3]: the scaled image lower bound
74 72 storres
    [4]: the scaled image upper bound
75 72 storres
    """
76 80 storres
    x = functionSa.variables()[0]
77 80 storres
    # Reassert f as a function (an not a mere expression).
78 80 storres
79 72 storres
    # Scalling the domain -> [1,2[.
80 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
81 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
82 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
83 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
84 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
85 72 storres
    print "f: ", f
86 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
87 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
88 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
89 80 storres
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
90 80 storres
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
91 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
92 72 storres
    #
93 72 storres
    # Scalling the image -> [1,2[.
94 72 storres
    flbSa = f(lowerBoundSa).n()
95 72 storres
    fubSa = f(upperBoundSa).n()
96 72 storres
    if flbSa <= fubSa: # Increasing
97 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
98 72 storres
    else: # Decreasing
99 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
100 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
101 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
102 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
103 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
104 72 storres
    iis = invImageScalingExpressionSa.function(x)
105 72 storres
    fff = iis.subs({x:ff})
106 72 storres
    print "fff:", fff,
107 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
108 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
109 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
110 72 storres
111 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
112 79 storres
    # Create a polynomial over the rationals.
113 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
114 79 storres
    return(polynomialRing(polyOfFloat))
115 79 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat
116 81 storres
117 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
118 63 storres
                                      lowerBoundSa,
119 60 storres
                                      upperBoundSa, floatingPointPrecSa,
120 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
121 60 storres
    """
122 60 storres
    Under the assumption that:
123 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
124 60 storres
    - lowerBound and upperBound belong to the same binade.
125 60 storres
    from a:
126 60 storres
    - function;
127 60 storres
    - a degree
128 60 storres
    - a pair of bounds;
129 60 storres
    - the floating-point precision we work on;
130 60 storres
    - the internal Sollya precision;
131 64 storres
    - the requested approximation error
132 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
133 61 storres
    It return a list of tuples, each made of:
134 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
135 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
136 61 storres
    - the approximation interval;
137 72 storres
    - the center, x0, of the interval;
138 61 storres
    - the corresponding approximation error.
139 60 storres
    """
140 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
141 80 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa, \
142 80 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) = \
143 80 storres
                slz_compute_scaled_function(functionSa, \
144 80 storres
                                            lowerBoundSa, \
145 80 storres
                                            upperBoundSa, \
146 80 storres
                                            floatingPointPrecSa)
147 60 storres
    #
148 60 storres
    resultArray = []
149 60 storres
    #
150 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
151 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
152 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
153 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
154 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
155 61 storres
                                                  scaledUpperBoundSa)
156 61 storres
    # Compute the first Taylor expansion.
157 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
158 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
159 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
160 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
161 64 storres
    # Change variable stuff
162 62 storres
    changeVarExpressionSo = sollya_lib_build_function_sub(
163 62 storres
                              sollya_lib_build_function_free_variable(),
164 62 storres
                              sollya_lib_copy_obj(intervalCenterSo))
165 62 storres
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
166 64 storres
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
167 64 storres
                         maxErrorSo))
168 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
169 60 storres
                                              upperBoundSa.parent().precision()))
170 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
171 81 storres
    # Compute the next upper bound.
172 81 storres
    # If the error of approximation is more than half of the target,
173 81 storres
    # use the same interval.
174 81 storres
    # If it is less, increase it a bit.
175 81 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
176 81 storres
    currentErrorRatio = approxPrecSa / errorSa
177 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
178 81 storres
    if currentErrorRatio  < 2 :
179 81 storres
        currentScaledUpperBoundSa += \
180 81 storres
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
181 81 storres
    else:
182 81 storres
        currentScaledUpperBoundSa += \
183 81 storres
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
184 81 storres
                         * currentErrorRatio.log2() * 2
185 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
186 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
187 61 storres
    # Compute the other expansions.
188 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
189 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
190 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
191 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
192 60 storres
                                            currentScaledLowerBoundSa,
193 81 storres
                                            currentScaledUpperBoundSa,
194 81 storres
                                            approxPrecSa,
195 60 storres
                                            internalSollyaPrecSa)
196 64 storres
        # Change variable stuff
197 64 storres
        changeVarExpressionSo = sollya_lib_build_function_sub(
198 64 storres
                                  sollya_lib_build_function_free_variable(),
199 64 storres
                                  sollya_lib_copy_obj(intervalCenterSo))
200 64 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
201 64 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
202 64 storres
                            intervalCenterSo, maxErrorSo))
203 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
204 81 storres
        # Compute the next upper bound.
205 81 storres
        # If the error of approximation is more than half of the target,
206 81 storres
        # use the same interval.
207 81 storres
        # If it is less, increase it a bit.
208 81 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
209 81 storres
        currentErrorRatio = approxPrecSa / errorSa
210 81 storres
        if currentErrorRatio  < RR('1.5') :
211 81 storres
            currentScaledUpperBoundSa = \
212 81 storres
                            boundsSa.endpoints()[1] + \
213 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
214 81 storres
        elif currentErrorRatio < 2:
215 81 storres
            currentScaledUpperBoundSa = \
216 81 storres
                            boundsSa.endpoints()[1] + \
217 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
218 81 storres
                             * currentErrorRatio.log2()
219 81 storres
        else:
220 81 storres
            currentScaledUpperBoundSa = \
221 81 storres
                            boundsSa.endpoints()[1] + \
222 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
223 81 storres
                             * currentErrorRatio.log2() * 2
224 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
225 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
226 60 storres
    sollya_lib_clear_obj(functionSo)
227 60 storres
    sollya_lib_clear_obj(degreeSo)
228 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
229 60 storres
    return(resultArray)
230 81 storres
# End slz_get_intervals_and_polynomials
231 60 storres
232 81 storres
233 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
234 61 storres
    """
235 61 storres
    Compute the scaling expression to map an interval that span only
236 62 storres
    a binade to [1, 2) and the inverse expression as well.
237 62 storres
    Not very sure that the transformation makes sense for negative numbers.
238 61 storres
    """
239 62 storres
    # The scaling offset is only used for negative numbers.
240 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
241 61 storres
        if boundsInterval.endpoints()[0] >= 0:
242 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
243 62 storres
            invScalingCoeff = 1/scalingCoeff
244 80 storres
            return((scalingCoeff * expVar,
245 80 storres
                    invScalingCoeff * expVar))
246 60 storres
        else:
247 62 storres
            scalingCoeff = \
248 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
249 62 storres
            scalingOffset = -3 * scalingCoeff
250 80 storres
            return((scalingCoeff * expVar + scalingOffset,
251 80 storres
                    1/scalingCoeff * expVar + 3))
252 61 storres
    else:
253 61 storres
        if boundsInterval.endpoints()[0] >= 0:
254 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
255 61 storres
            scalingOffset = 0
256 80 storres
            return((scalingCoeff * expVar,
257 80 storres
                    1/scalingCoeff * expVar))
258 61 storres
        else:
259 62 storres
            scalingCoeff = \
260 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
261 62 storres
            scalingOffset =  -3 * scalingCoeff
262 62 storres
            #scalingOffset = 0
263 80 storres
            return((scalingCoeff * expVar + scalingOffset,
264 80 storres
                    1/scalingCoeff * expVar + 3))
265 61 storres
266 61 storres
267 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
268 72 storres
    """
269 72 storres
    Compute the Sage version of the Taylor polynomial and it's
270 72 storres
    companion data (interval, center...)
271 72 storres
    The input parameter is a five elements tuple:
272 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
273 79 storres
           real ring;
274 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
275 79 storres
           over a real ring;
276 72 storres
    - [2]: the interval (as Sollya range);
277 72 storres
    - [3]: the interval center;
278 72 storres
    - [4]: the approximation error.
279 72 storres
280 72 storres
    The function return a 5 elements tuple: formed with all the
281 72 storres
    input elements converted into their Sollya counterpart.
282 72 storres
    """
283 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
284 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
285 60 storres
    intervalSa = \
286 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
287 60 storres
    centerSa = \
288 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
289 60 storres
    errorSa = \
290 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
291 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
292 83 storres
    # End slz_interval_and_polynomial_to_sage
293 62 storres
294 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
295 80 storres
                                                precision,
296 80 storres
                                                targetHardnessToRound,
297 80 storres
                                                variable1,
298 80 storres
                                                variable2):
299 80 storres
    """
300 80 storres
    Creates a new polynomial with integer coefficients for use with the
301 80 storres
    Coppersmith method.
302 80 storres
    A the same time it computes :
303 80 storres
    - 2^K (N);
304 80 storres
    - 2^k
305 80 storres
    - lcm
306 80 storres
    """
307 80 storres
    # Create a new integer polynomial ring.
308 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
309 80 storres
    # Coefficients are issued in the increasing power order.
310 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
311 80 storres
    # Build the list of number we compute the lcmm of.
312 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
313 80 storres
    coefficientDenominators.append(2^precision)
314 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
315 80 storres
    leastCommonMultiple = sro_lcmm(coefficientDenominators)
316 80 storres
    # Compute the lcm
317 80 storres
    leastCommonMultiple = sro_lcmm(coefficientDenominators)
318 80 storres
    # Compute the expression corresponding to the new polynomial
319 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
320 80 storres
    print coefficientNumerators
321 80 storres
    polynomialExpression = 0
322 80 storres
    power = 0
323 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
324 80 storres
    # exhausted.
325 80 storres
    for numerator, denominator in \
326 80 storres
                            zip(coefficientNumerators, coefficientDenominators):
327 80 storres
        multiplicator = leastCommonMultiple / denominator
328 80 storres
        newCoefficient = numerator * multiplicator
329 80 storres
        polynomialExpression += newCoefficient * variable1^power
330 80 storres
        power +=1
331 80 storres
    polynomialExpression += - variable2
332 80 storres
    return (IP(polynomialExpression),
333 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
334 80 storres
            leastCommonMultiple / 2 ^(targetHardnessToRound + 1), # tBound
335 80 storres
            leastCommonMultiple)
336 80 storres
337 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
338 79 storres
339 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
340 79 storres
                                          precision):
341 79 storres
    """
342 79 storres
    Makes a variable substitution into the input polynomial so that the output
343 79 storres
    polynomial can take integer arguments.
344 79 storres
    All variables of the input polynomial "have precision p". That is to say
345 79 storres
    that they are rationals with denominator == 2^precision: x = y/2^precision
346 79 storres
    We "incorporate" these denominators into the coefficients with,
347 79 storres
    respectively, the "right" power.
348 79 storres
    """
349 79 storres
    polynomialField = ratPolyOfRat.parent()
350 79 storres
    polynomialVariable = rationalPolynomial.variables()[0]
351 79 storres
    print "The polynomial field is:", polynomialField
352 79 storres
    return \
353 79 storres
        polynomialField(rationalPolynomial.subs({polynomialVariable : \
354 79 storres
                                   polynomialVariable/2^(precision-1)}))
355 79 storres
356 79 storres
    # Return a tuple:
357 79 storres
    # - the bivariate integer polynomial in (i,j);
358 79 storres
    # - 2^K
359 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
360 79 storres
361 62 storres
print "sageSLZ loaded..."