Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (21,26 ko)

1 90 storres
"""
2 98 storres
module:: sageSLZ.sage
3 90 storres
4 90 storres
Sage core function needed for the implementation of SLZ.
5 90 storres
6 90 storres
Created on 2013-08
7 90 storres
8 90 storres
moduleauthor:: S.T.
9 90 storres
"""
10 87 storres
print "sageSLZ loading..."
11 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
12 61 storres
                                        upperBoundSa, approxPrecSa,
13 61 storres
                                        sollyaPrecSa=None):
14 61 storres
    """
15 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
16 61 storres
    a polynomial that approximates the function on a an interval starting
17 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
18 61 storres
    approximates with the expected precision.
19 61 storres
    The interval upper bound is lowered until the expected approximation
20 61 storres
    precision is reached.
21 61 storres
    The polynomial, the bounds, the center of the interval and the error
22 61 storres
    are returned.
23 61 storres
    """
24 61 storres
    RRR = lowerBoundSa.parent()
25 61 storres
    intervalShrinkConstFactorSa = RRR('0.5')
26 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
27 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
28 61 storres
    currentUpperBoundSa = upperBoundSa
29 61 storres
    currentLowerBoundSa = lowerBoundSa
30 61 storres
    # What we want here is the polynomial without the variable change,
31 61 storres
    # since our actual variable will be x-intervalCenter defined over the
32 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
33 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
34 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
35 61 storres
                                                    currentRangeSo,
36 61 storres
                                                    absoluteErrorTypeSo)
37 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
38 61 storres
    while maxErrorSa > approxPrecSa:
39 61 storres
        sollya_lib_clear_obj(maxErrorSo)
40 81 storres
        sollya_lib_clear_obj(polySo)
41 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
42 81 storres
        shrinkFactorSa = RRR('5.0')/(maxErrorSa/approxPrecSa).log2().abs()
43 81 storres
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
44 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
45 61 storres
        #print "Error ratio: ", errorRatioSa
46 81 storres
47 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
48 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
49 81 storres
            #print "Fixed"
50 61 storres
        else:
51 81 storres
            actualShrinkFactorSa = shrinkFactorSa
52 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
53 81 storres
            #print shrinkFactorSa, maxErrorSa
54 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
55 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
56 81 storres
                                   actualShrinkFactorSa
57 71 storres
        #print "Current upper bound:", currentUpperBoundSa
58 61 storres
        sollya_lib_clear_obj(currentRangeSo)
59 61 storres
        sollya_lib_clear_obj(polySo)
60 86 storres
        if currentUpperBoundSa <= currentLowerBoundSa:
61 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
62 86 storres
            print "Can't find an interval."
63 86 storres
            print "Use either or both a higher polynomial degree or a higher",
64 86 storres
            print "internal precision."
65 86 storres
            print "Aborting!"
66 86 storres
            return (None, None, None, None)
67 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
68 61 storres
                                                      currentUpperBoundSa)
69 86 storres
        # print "New interval:",
70 86 storres
        # pobyso_autoprint(currentRangeSo)
71 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
72 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
73 61 storres
                                                        currentRangeSo,
74 61 storres
                                                        absoluteErrorTypeSo)
75 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
76 85 storres
        #print "Max errorSo:",
77 85 storres
        #pobyso_autoprint(maxErrorSo)
78 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
79 85 storres
        #print "Max errorSa:", maxErrorSa
80 85 storres
        #print "Sollya prec:",
81 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
82 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
83 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
84 81 storres
# End slz_compute_polynomial_and_interval
85 61 storres
86 98 storres
def slz_compute_reduced_polynomials(reducedMatrix,
87 98 storres
                                    knownMonomials,
88 98 storres
                                    polynomialRing,
89 98 storres
                                    var1Bound,
90 98 storres
                                    var2Bound, ):
91 98 storres
    """
92 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
93 98 storres
    from the bounds of each variable, compute the corresponding polynomials
94 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
95 98 storres
    """
96 98 storres
    # TODO: check input arguments.
97 98 storres
    if len(knownMonomials) == 0:
98 98 storres
        return []
99 98 storres
    (var1, var2) = knownMonomials[0].variables()[0:2]
100 98 storres
    print "Variable 1:", var1;
101 98 storres
    print "Variable 2:", var2
102 98 storres
    reducedPolynomials = []
103 98 storres
    for matrixRow in reducedMatrix.rows():
104 98 storres
        currentExpression = 0
105 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
106 98 storres
            currentCoefficient = matrixRow[colIndex]
107 98 storres
            print knownMonomials[colIndex]
108 98 storres
            currentMonomialAsMvp = polynomialRing(knownMonomials[colIndex])
109 98 storres
            print "Monomial as multivariate polynomial:", \
110 98 storres
            currentMonomialAsMvp, type(currentMonomialAsMvp)
111 98 storres
            degreeInVar1 = currentMonomialAsMvp.degree(var1)
112 98 storres
            print "Degree in var", var1, ":", degreeInVar1
113 98 storres
            degreeInVar2 = currentMonomialAsMvp.degree(var2)
114 98 storres
            if degreeInVar1 != 0:
115 98 storres
                currentCoefficient  /= (var1Bound^degreeInVar1)
116 98 storres
            if degreeInVar2 != 0:
117 98 storres
                currentCoefficient /= (var2Bound^degreeInVar2)
118 98 storres
            print "Current Expression:", currentExpression
119 98 storres
            currentExpression += currentCoefficient * \
120 98 storres
                currentMonomialAsMvp
121 98 storres
        reducedPolynomials.append(currentExpression)
122 98 storres
    return reducedPolynomials
123 98 storres
# End slz_compute_reduced_polynomials
124 98 storres
125 72 storres
def slz_compute_scaled_function(functionSa, \
126 72 storres
                                      lowerBoundSa, \
127 72 storres
                                      upperBoundSa, \
128 72 storres
                                      floatingPointPrecSa):
129 72 storres
    """
130 72 storres
    From a function, compute the scaled function whose domain
131 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
132 72 storres
    Return a tuple:
133 72 storres
    [0]: the scaled function
134 72 storres
    [1]: the scaled domain lower bound
135 72 storres
    [2]: the scaled domain upper bound
136 72 storres
    [3]: the scaled image lower bound
137 72 storres
    [4]: the scaled image upper bound
138 72 storres
    """
139 80 storres
    x = functionSa.variables()[0]
140 80 storres
    # Reassert f as a function (an not a mere expression).
141 80 storres
142 72 storres
    # Scalling the domain -> [1,2[.
143 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
144 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
145 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
146 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
147 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
148 72 storres
    print "f: ", f
149 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
150 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
151 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
152 80 storres
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
153 80 storres
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
154 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
155 72 storres
    #
156 72 storres
    # Scalling the image -> [1,2[.
157 72 storres
    flbSa = f(lowerBoundSa).n()
158 72 storres
    fubSa = f(upperBoundSa).n()
159 72 storres
    if flbSa <= fubSa: # Increasing
160 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
161 72 storres
    else: # Decreasing
162 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
163 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
164 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
165 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
166 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
167 72 storres
    iis = invImageScalingExpressionSa.function(x)
168 72 storres
    fff = iis.subs({x:ff})
169 72 storres
    print "fff:", fff,
170 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
171 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
172 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
173 72 storres
174 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
175 79 storres
    # Create a polynomial over the rationals.
176 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
177 79 storres
    return(polynomialRing(polyOfFloat))
178 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
179 81 storres
180 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
181 63 storres
                                      lowerBoundSa,
182 60 storres
                                      upperBoundSa, floatingPointPrecSa,
183 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
184 60 storres
    """
185 60 storres
    Under the assumption that:
186 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
187 60 storres
    - lowerBound and upperBound belong to the same binade.
188 60 storres
    from a:
189 60 storres
    - function;
190 60 storres
    - a degree
191 60 storres
    - a pair of bounds;
192 60 storres
    - the floating-point precision we work on;
193 60 storres
    - the internal Sollya precision;
194 64 storres
    - the requested approximation error
195 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
196 61 storres
    It return a list of tuples, each made of:
197 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
198 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
199 61 storres
    - the approximation interval;
200 72 storres
    - the center, x0, of the interval;
201 61 storres
    - the corresponding approximation error.
202 60 storres
    """
203 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
204 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
205 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
206 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
207 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
208 80 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa, \
209 80 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) = \
210 80 storres
                slz_compute_scaled_function(functionSa, \
211 80 storres
                                            lowerBoundSa, \
212 80 storres
                                            upperBoundSa, \
213 80 storres
                                            floatingPointPrecSa)
214 60 storres
    #
215 60 storres
    resultArray = []
216 60 storres
    #
217 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
218 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
219 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
220 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
221 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
222 61 storres
                                                  scaledUpperBoundSa)
223 61 storres
    # Compute the first Taylor expansion.
224 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
225 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
226 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
227 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
228 86 storres
    if polySo is None:
229 86 storres
        print "Aborting"
230 86 storres
        return None
231 64 storres
    # Change variable stuff
232 62 storres
    changeVarExpressionSo = sollya_lib_build_function_sub(
233 62 storres
                              sollya_lib_build_function_free_variable(),
234 62 storres
                              sollya_lib_copy_obj(intervalCenterSo))
235 62 storres
    polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
236 64 storres
    resultArray.append((polySo, polyVarChangedSo, boundsSo, intervalCenterSo,\
237 64 storres
                         maxErrorSo))
238 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
239 60 storres
                                              upperBoundSa.parent().precision()))
240 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
241 81 storres
    # Compute the next upper bound.
242 81 storres
    # If the error of approximation is more than half of the target,
243 81 storres
    # use the same interval.
244 81 storres
    # If it is less, increase it a bit.
245 81 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
246 81 storres
    currentErrorRatio = approxPrecSa / errorSa
247 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
248 81 storres
    if currentErrorRatio  < 2 :
249 81 storres
        currentScaledUpperBoundSa += \
250 81 storres
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
251 81 storres
    else:
252 81 storres
        currentScaledUpperBoundSa += \
253 81 storres
            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
254 81 storres
                         * currentErrorRatio.log2() * 2
255 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
256 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
257 61 storres
    # Compute the other expansions.
258 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
259 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
260 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
261 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
262 60 storres
                                            currentScaledLowerBoundSa,
263 81 storres
                                            currentScaledUpperBoundSa,
264 81 storres
                                            approxPrecSa,
265 60 storres
                                            internalSollyaPrecSa)
266 64 storres
        # Change variable stuff
267 64 storres
        changeVarExpressionSo = sollya_lib_build_function_sub(
268 64 storres
                                  sollya_lib_build_function_free_variable(),
269 64 storres
                                  sollya_lib_copy_obj(intervalCenterSo))
270 64 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
271 64 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
272 64 storres
                            intervalCenterSo, maxErrorSo))
273 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
274 81 storres
        # Compute the next upper bound.
275 81 storres
        # If the error of approximation is more than half of the target,
276 81 storres
        # use the same interval.
277 81 storres
        # If it is less, increase it a bit.
278 81 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
279 81 storres
        currentErrorRatio = approxPrecSa / errorSa
280 81 storres
        if currentErrorRatio  < RR('1.5') :
281 81 storres
            currentScaledUpperBoundSa = \
282 81 storres
                            boundsSa.endpoints()[1] + \
283 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0])
284 81 storres
        elif currentErrorRatio < 2:
285 81 storres
            currentScaledUpperBoundSa = \
286 81 storres
                            boundsSa.endpoints()[1] + \
287 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
288 81 storres
                             * currentErrorRatio.log2()
289 81 storres
        else:
290 81 storres
            currentScaledUpperBoundSa = \
291 81 storres
                            boundsSa.endpoints()[1] + \
292 81 storres
                            (boundsSa.endpoints()[1] - boundsSa.endpoints()[0]) \
293 81 storres
                             * currentErrorRatio.log2() * 2
294 85 storres
        # Test for insufficient precision.
295 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
296 85 storres
            print "Can't shrink the interval anymore!"
297 85 storres
            print "You should consider increasing the Sollya internal precision"
298 85 storres
            print "or the polynomial degree."
299 85 storres
            print "Giving up!"
300 85 storres
            sollya_lib_clear_obj(functionSo)
301 85 storres
            sollya_lib_clear_obj(degreeSo)
302 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
303 85 storres
            return None
304 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
305 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
306 60 storres
    sollya_lib_clear_obj(functionSo)
307 60 storres
    sollya_lib_clear_obj(degreeSo)
308 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
309 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
310 85 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
311 60 storres
    return(resultArray)
312 81 storres
# End slz_get_intervals_and_polynomials
313 60 storres
314 81 storres
315 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
316 61 storres
    """
317 61 storres
    Compute the scaling expression to map an interval that span only
318 62 storres
    a binade to [1, 2) and the inverse expression as well.
319 62 storres
    Not very sure that the transformation makes sense for negative numbers.
320 61 storres
    """
321 62 storres
    # The scaling offset is only used for negative numbers.
322 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
323 61 storres
        if boundsInterval.endpoints()[0] >= 0:
324 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
325 62 storres
            invScalingCoeff = 1/scalingCoeff
326 80 storres
            return((scalingCoeff * expVar,
327 80 storres
                    invScalingCoeff * expVar))
328 60 storres
        else:
329 62 storres
            scalingCoeff = \
330 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
331 62 storres
            scalingOffset = -3 * scalingCoeff
332 80 storres
            return((scalingCoeff * expVar + scalingOffset,
333 80 storres
                    1/scalingCoeff * expVar + 3))
334 61 storres
    else:
335 61 storres
        if boundsInterval.endpoints()[0] >= 0:
336 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
337 61 storres
            scalingOffset = 0
338 80 storres
            return((scalingCoeff * expVar,
339 80 storres
                    1/scalingCoeff * expVar))
340 61 storres
        else:
341 62 storres
            scalingCoeff = \
342 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
343 62 storres
            scalingOffset =  -3 * scalingCoeff
344 62 storres
            #scalingOffset = 0
345 80 storres
            return((scalingCoeff * expVar + scalingOffset,
346 80 storres
                    1/scalingCoeff * expVar + 3))
347 61 storres
348 61 storres
349 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
350 72 storres
    """
351 72 storres
    Compute the Sage version of the Taylor polynomial and it's
352 72 storres
    companion data (interval, center...)
353 72 storres
    The input parameter is a five elements tuple:
354 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
355 79 storres
           real ring;
356 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
357 79 storres
           over a real ring;
358 72 storres
    - [2]: the interval (as Sollya range);
359 72 storres
    - [3]: the interval center;
360 72 storres
    - [4]: the approximation error.
361 72 storres
362 72 storres
    The function return a 5 elements tuple: formed with all the
363 72 storres
    input elements converted into their Sollya counterpart.
364 72 storres
    """
365 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
366 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
367 60 storres
    intervalSa = \
368 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
369 60 storres
    centerSa = \
370 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
371 60 storres
    errorSa = \
372 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
373 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
374 83 storres
    # End slz_interval_and_polynomial_to_sage
375 62 storres
376 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
377 80 storres
                                                precision,
378 80 storres
                                                targetHardnessToRound,
379 80 storres
                                                variable1,
380 80 storres
                                                variable2):
381 80 storres
    """
382 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
383 90 storres
     with the Coppersmith method.
384 80 storres
    A the same time it computes :
385 80 storres
    - 2^K (N);
386 90 storres
    - 2^k (bound on the second variable)
387 80 storres
    - lcm
388 90 storres
389 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
390 90 storres
                         variables.
391 90 storres
    :param precision: the precision of the floating-point coefficients.
392 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
393 90 storres
    :param variable1: the first variable of the polynomial (an expression).
394 90 storres
    :param variable2: the second variable of the polynomial (an expression).
395 90 storres
396 90 storres
    :returns: a 4 elements tuple:
397 90 storres
                - the polynomial;
398 91 storres
                - the modulus (N);
399 91 storres
                - the t bound;
400 90 storres
                - the lcm used to compute the integral coefficients and the
401 90 storres
                  module.
402 80 storres
    """
403 80 storres
    # Create a new integer polynomial ring.
404 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
405 80 storres
    # Coefficients are issued in the increasing power order.
406 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
407 91 storres
    # Print the reversed list for debugging.
408 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
409 94 storres
    # Build the list of number we compute the lcm of.
410 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
411 80 storres
    coefficientDenominators.append(2^precision)
412 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
413 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
414 80 storres
    # Compute the expression corresponding to the new polynomial
415 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
416 91 storres
    #print coefficientNumerators
417 80 storres
    polynomialExpression = 0
418 80 storres
    power = 0
419 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
420 80 storres
    # exhausted.
421 80 storres
    for numerator, denominator in \
422 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
423 80 storres
        multiplicator = leastCommonMultiple / denominator
424 80 storres
        newCoefficient = numerator * multiplicator
425 80 storres
        polynomialExpression += newCoefficient * variable1^power
426 80 storres
        power +=1
427 80 storres
    polynomialExpression += - variable2
428 80 storres
    return (IP(polynomialExpression),
429 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
430 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
431 91 storres
            leastCommonMultiple) # If we want to make test computations.
432 80 storres
433 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
434 79 storres
435 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
436 79 storres
                                          precision):
437 79 storres
    """
438 79 storres
    Makes a variable substitution into the input polynomial so that the output
439 79 storres
    polynomial can take integer arguments.
440 79 storres
    All variables of the input polynomial "have precision p". That is to say
441 79 storres
    that they are rationals with denominator == 2^precision: x = y/2^precision
442 79 storres
    We "incorporate" these denominators into the coefficients with,
443 79 storres
    respectively, the "right" power.
444 79 storres
    """
445 79 storres
    polynomialField = ratPolyOfRat.parent()
446 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
447 91 storres
    #print "The polynomial field is:", polynomialField
448 79 storres
    return \
449 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
450 79 storres
                                   polynomialVariable/2^(precision-1)}))
451 79 storres
452 79 storres
    # Return a tuple:
453 79 storres
    # - the bivariate integer polynomial in (i,j);
454 79 storres
    # - 2^K
455 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
456 79 storres
457 87 storres
print "\t...sageSLZ loaded"