Statistiques
| Révision :

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

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