Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (45,8 ko)

1 115 storres
r"""
2 115 storres
Sage core functions needed for the implementation of SLZ.
3 90 storres
4 115 storres
AUTHORS:
5 115 storres
- S.T. (2013-08): initial version
6 90 storres
7 115 storres
Examples:
8 119 storres
9 119 storres
TODO::
10 90 storres
"""
11 87 storres
print "sageSLZ loading..."
12 115 storres
#
13 115 storres
def slz_check_htr_value(function, htrValue, lowerBound, upperBound, precision, \
14 115 storres
                        degree, targetHardnessToRound, alpha):
15 115 storres
    """
16 115 storres
    Check an Hard-to-round value.
17 124 storres
    TODO::
18 124 storres
    Full rewriting: this is hardly a draft.
19 115 storres
    """
20 115 storres
    polyApproxPrec = targetHardnessToRound + 1
21 115 storres
    polyTargetHardnessToRound = targetHardnessToRound + 1
22 115 storres
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
23 115 storres
    RRR = htrValue.parent()
24 115 storres
    #
25 115 storres
    ## Compute the scaled function.
26 115 storres
    fff = slz_compute_scaled_function(f, lowerBound, upperBound, precision)[0]
27 115 storres
    print "Scaled function:", fff
28 115 storres
    #
29 115 storres
    ## Compute the scaling.
30 115 storres
    boundsIntervalRifSa = RealIntervalField(precision)
31 115 storres
    domainBoundsInterval = boundsIntervalRifSa(lowerBound, upperBound)
32 115 storres
    scalingExpressions = \
33 115 storres
        slz_interval_scaling_expression(domainBoundsInterval, i)
34 115 storres
    #
35 115 storres
    ## Get the polynomials, bounds, etc. for all the interval.
36 115 storres
    resultListOfTuplesOfSo = \
37 115 storres
        slz_get_intervals_and_polynomials(f, degree, lowerBound, upperBound, \
38 115 storres
                                          precision, internalSollyaPrec,\
39 115 storres
                                          2^-(polyApproxPrec))
40 115 storres
    #
41 115 storres
    ## We only want one interval.
42 115 storres
    if len(resultListOfTuplesOfSo) > 1:
43 115 storres
        print "Too many intervals! Aborting!"
44 115 storres
        exit
45 115 storres
    #
46 115 storres
    ## Get the first tuple of Sollya objects as Sage objects.
47 115 storres
    firstTupleSa = \
48 115 storres
        slz_interval_and_polynomial_to_sage(resultListOfTuplesOfSo[0])
49 115 storres
    pobyso_set_canonical_on()
50 115 storres
    #
51 115 storres
    print "Floatting point polynomial:", firstTupleSa[0]
52 115 storres
    print "with coefficients precision:", firstTupleSa[0].base_ring().prec()
53 115 storres
    #
54 115 storres
    ## From a polynomial over a real ring, create a polynomial over the
55 115 storres
    #  rationals ring.
56 115 storres
    rationalPolynomial = \
57 115 storres
        slz_float_poly_of_float_to_rat_poly_of_rat(firstTupleSa[0])
58 115 storres
    print "Rational polynomial:", rationalPolynomial
59 115 storres
    #
60 115 storres
    ## Create a polynomial over the rationals that will take integer
61 115 storres
    # variables instead of rational.
62 115 storres
    rationalPolynomialOfIntegers = \
63 115 storres
        slz_rat_poly_of_rat_to_rat_poly_of_int(rationalPolynomial, precision)
64 115 storres
    print "Type:", type(rationalPolynomialOfIntegers)
65 115 storres
    print "Rational polynomial of integers:", rationalPolynomialOfIntegers
66 115 storres
    #
67 115 storres
    ## Check the rational polynomial of integers variables.
68 115 storres
    # (check against the scaled function).
69 115 storres
    toIntegerFactor = 2^(precision-1)
70 115 storres
    intervalCenterAsIntegerSa = int(firstTupleSa[3] * toIntegerFactor)
71 115 storres
    print "Interval center as integer:", intervalCenterAsIntegerSa
72 115 storres
    lowerBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[0] * \
73 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
74 115 storres
    upperBoundAsIntegerSa = int(firstTupleSa[2].endpoints()[1] * \
75 115 storres
                                toIntegerFactor) - intervalCenterAsIntegerSa
76 115 storres
    print "Lower bound as integer:", lowerBoundAsIntegerSa
77 115 storres
    print "Upper bound as integer:", upperBoundAsIntegerSa
78 115 storres
    print "Image of the lower bound by the scaled function", \
79 115 storres
            fff(firstTupleSa[2].endpoints()[0])
80 115 storres
    print "Image of the lower bound by the approximation polynomial of ints:", \
81 115 storres
            RRR(rationalPolynomialOfIntegers(lowerBoundAsIntegerSa))
82 115 storres
    print "Image of the center by the scaled function", fff(firstTupleSa[3])
83 115 storres
    print "Image of the center by the approximation polynomial of ints:", \
84 115 storres
            RRR(rationalPolynomialOfIntegers(0))
85 115 storres
    print "Image of the upper bound by the scaled function", \
86 115 storres
            fff(firstTupleSa[2].endpoints()[1])
87 115 storres
    print "Image of the upper bound by the approximation polynomial of ints:", \
88 115 storres
            RRR(rationalPolynomialOfIntegers(upperBoundAsIntegerSa))
89 115 storres
90 115 storres
# End slz_check_htr_value.
91 122 storres
92 115 storres
#
93 121 storres
def slz_compute_binade_bounds(number, emin, emax=sys.maxint):
94 119 storres
    """
95 119 storres
    For given "real number", compute the bounds of the binade it belongs to.
96 121 storres
97 121 storres
    NOTE::
98 121 storres
        When number >= 2^(emax+1), we return the "fake" binade
99 121 storres
        [2^(emax+1), +infinity]. Ditto for number <= -2^(emax+1)
100 125 storres
        with interval [-infinity, -2^(emax+1)]. We want to distinguish
101 125 storres
        this case from that of "really" invalid arguments.
102 121 storres
103 119 storres
    """
104 121 storres
    # Check the parameters.
105 125 storres
    # RealNumbers or RealNumber offspring only.
106 125 storres
    # The execption construction is necessary since not all objects have
107 125 storres
    # the mro() method. sage.rings.real_mpfr.RealNumber do.
108 124 storres
    try:
109 124 storres
        classTree = [number.__class__] + number.mro()
110 124 storres
        if not sage.rings.real_mpfr.RealNumber in classTree:
111 124 storres
            return None
112 124 storres
    except AttributeError:
113 121 storres
        return None
114 121 storres
    # Non zero negative integers only for emin.
115 121 storres
    if emin >= 0 or int(emin) != emin:
116 121 storres
        return None
117 121 storres
    # Non zero positive integers only for emax.
118 121 storres
    if emax <= 0 or int(emax) != emax:
119 121 storres
        return None
120 121 storres
    precision = number.precision()
121 121 storres
    RF  = RealField(precision)
122 125 storres
    if number == 0:
123 125 storres
        return (RF(0),RF(2^(emin)) - RF(2^(emin-precision)))
124 121 storres
    # A more precise RealField is needed to avoid unwanted rounding effects
125 121 storres
    # when computing number.log2().
126 121 storres
    RRF = RealField(max(2048, 2 * precision))
127 121 storres
    # number = 0 special case, the binade bounds are
128 121 storres
    # [0, 2^emin - 2^(emin-precision)]
129 121 storres
    # Begin general case
130 119 storres
    l2 = RRF(number).abs().log2()
131 121 storres
    # Another special one: beyond largest representable -> "Fake" binade.
132 121 storres
    if l2 >= emax + 1:
133 121 storres
        if number > 0:
134 125 storres
            return (RF(2^(emax+1)), RF(+infinity) )
135 121 storres
        else:
136 121 storres
            return (RF(-infinity), -RF(2^(emax+1)))
137 119 storres
    offset = int(l2)
138 121 storres
    # number.abs() >= 1.
139 119 storres
    if l2 >= 0:
140 119 storres
        if number >= 0:
141 119 storres
            lb = RF(2^offset)
142 119 storres
            ub = RF(2^(offset + 1) - 2^(-precision+offset+1))
143 119 storres
        else: #number < 0
144 119 storres
            lb = -RF(2^(offset + 1) - 2^(-precision+offset+1))
145 119 storres
            ub = -RF(2^offset)
146 121 storres
    else: # log2 < 0, number.abs() < 1.
147 119 storres
        if l2 < emin: # Denormal
148 121 storres
           # print "Denormal:", l2
149 119 storres
            if number >= 0:
150 119 storres
                lb = RF(0)
151 119 storres
                ub = RF(2^(emin)) - RF(2^(emin-precision))
152 119 storres
            else: # number <= 0
153 119 storres
                lb = - RF(2^(emin)) + RF(2^(emin-precision))
154 119 storres
                ub = RF(0)
155 119 storres
        elif l2 > emin: # Normal number other than +/-2^emin.
156 119 storres
            if number >= 0:
157 121 storres
                if int(l2) == l2:
158 121 storres
                    lb = RF(2^(offset))
159 121 storres
                    ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
160 121 storres
                else:
161 121 storres
                    lb = RF(2^(offset-1))
162 121 storres
                    ub = RF(2^(offset)) - RF(2^(-precision+offset))
163 119 storres
            else: # number < 0
164 121 storres
                if int(l2) == l2: # Binade limit.
165 121 storres
                    lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
166 121 storres
                    ub = -RF(2^(offset))
167 121 storres
                else:
168 121 storres
                    lb = -RF(2^(offset) - 2^(-precision+offset))
169 121 storres
                    ub = -RF(2^(offset-1))
170 121 storres
        else: # l2== emin, number == +/-2^emin
171 119 storres
            if number >= 0:
172 119 storres
                lb = RF(2^(offset))
173 119 storres
                ub = RF(2^(offset+1)) - RF(2^(-precision+offset+1))
174 119 storres
            else: # number < 0
175 119 storres
                lb = -RF(2^(offset+1) - 2^(-precision+offset+1))
176 119 storres
                ub = -RF(2^(offset))
177 119 storres
    return (lb, ub)
178 119 storres
# End slz_compute_binade_bounds
179 119 storres
#
180 123 storres
def slz_compute_coppersmith_reduced_polynomials(inputPolynomial,
181 123 storres
                                                 alpha,
182 123 storres
                                                 N,
183 123 storres
                                                 iBound,
184 123 storres
                                                 tBound):
185 123 storres
    """
186 123 storres
    For a given set of arguments (see below), compute a list
187 123 storres
    of "reduced polynomials" that could be used to compute roots
188 123 storres
    of the inputPolynomial.
189 124 storres
    INPUT:
190 124 storres
191 124 storres
    - "inputPolynomial" -- (no default) a bivariate integer polynomial;
192 124 storres
    - "alpha" -- the alpha parameter of the Coppersmith algorithm;
193 124 storres
    - "N" -- the modulus;
194 124 storres
    - "iBound" -- the bound on the first variable;
195 124 storres
    - "tBound" -- the bound on the second variable.
196 124 storres
197 124 storres
    OUTPUT:
198 124 storres
199 124 storres
    A list of bivariate integer polynomial obtained using the Coppersmith
200 124 storres
    algorithm. The polynomials correspond to the rows of the LLL-reduce
201 124 storres
    reduced base that comply with the Coppersmith condition.
202 123 storres
    """
203 123 storres
    # Arguments check.
204 123 storres
    if iBound == 0 or tBound == 0:
205 123 storres
        return ()
206 123 storres
    # End arguments check.
207 123 storres
    nAtAlpha = N^alpha
208 123 storres
    ## Building polynomials for matrix.
209 123 storres
    polyRing   = inputPolynomial.parent()
210 123 storres
    # Whatever the 2 variables are actually called, we call them
211 123 storres
    # 'i' and 't' in all the variable names.
212 123 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
213 123 storres
    #print polyVars[0], type(polyVars[0])
214 123 storres
    initialPolynomial = inputPolynomial.subs({iVariable:iVariable * iBound,
215 123 storres
                                              tVariable:tVariable * tBound})
216 123 storres
    polynomialsList = \
217 123 storres
        spo_polynomial_to_polynomials_list_5(initialPolynomial,
218 123 storres
                                             alpha,
219 123 storres
                                             N,
220 123 storres
                                             iBound,
221 123 storres
                                             tBound,
222 123 storres
                                             0)
223 123 storres
    #print "Polynomials list:", polynomialsList
224 123 storres
    ## Building the proto matrix.
225 123 storres
    knownMonomials = []
226 123 storres
    protoMatrix    = []
227 123 storres
    for poly in polynomialsList:
228 123 storres
        spo_add_polynomial_coeffs_to_matrix_row(poly,
229 123 storres
                                                knownMonomials,
230 123 storres
                                                protoMatrix,
231 123 storres
                                                0)
232 123 storres
    matrixToReduce = spo_proto_to_row_matrix(protoMatrix)
233 123 storres
    #print matrixToReduce
234 123 storres
    ## Reduction and checking.
235 123 storres
    reducedMatrix = matrixToReduce.LLL(fp='fp')
236 123 storres
    isLLLReduced  = reducedMatrix.is_LLL_reduced()
237 123 storres
    if not isLLLReduced:
238 125 storres
        return set()
239 123 storres
    monomialsCount     = len(knownMonomials)
240 123 storres
    monomialsCountSqrt = sqrt(monomialsCount)
241 123 storres
    #print "Monomials count:", monomialsCount, monomialsCountSqrt.n()
242 123 storres
    #print reducedMatrix
243 123 storres
    ## Check the Coppersmith condition for each row and build the reduced
244 123 storres
    #  polynomials.
245 123 storres
    ccReducedPolynomialsList = []
246 123 storres
    for row in reducedMatrix.rows():
247 123 storres
        l2Norm = row.norm(2)
248 123 storres
        if (l2Norm * monomialsCountSqrt) < nAtAlpha:
249 123 storres
            #print (l2Norm * monomialsCountSqrt).n()
250 125 storres
            #print l2Norm.n()
251 123 storres
            ccReducedPolynomial = \
252 123 storres
                slz_compute_reduced_polynomial(row,
253 123 storres
                                               knownMonomials,
254 123 storres
                                               iVariable,
255 123 storres
                                               iBound,
256 123 storres
                                               tVariable,
257 123 storres
                                               tBound)
258 123 storres
            if not ccReducedPolynomial is None:
259 123 storres
                ccReducedPolynomialsList.append(ccReducedPolynomial)
260 123 storres
        else:
261 125 storres
            #print l2Norm.n() , ">", nAtAlpha
262 123 storres
            pass
263 123 storres
    if len(ccReducedPolynomialsList) < 2:
264 125 storres
        print "Less than 2 Coppersmith condition compliant vectors."
265 123 storres
        return ()
266 125 storres
267 125 storres
    #print ccReducedPolynomialsList
268 123 storres
    return ccReducedPolynomialsList
269 123 storres
# End slz_compute_coppersmith_reduced_polynomials
270 123 storres
271 122 storres
def slz_compute_integer_polynomial_modular_roots(inputPolynomial,
272 122 storres
                                                 alpha,
273 122 storres
                                                 N,
274 122 storres
                                                 iBound,
275 122 storres
                                                 tBound):
276 122 storres
    """
277 123 storres
    For a given set of arguments (see below), compute the polynomial modular
278 122 storres
    roots, if any.
279 124 storres
280 122 storres
    """
281 123 storres
    # Arguments check.
282 123 storres
    if iBound == 0 or tBound == 0:
283 123 storres
        return set()
284 123 storres
    # End arguments check.
285 122 storres
    nAtAlpha = N^alpha
286 122 storres
    ## Building polynomials for matrix.
287 122 storres
    polyRing   = inputPolynomial.parent()
288 122 storres
    # Whatever the 2 variables are actually called, we call them
289 122 storres
    # 'i' and 't' in all the variable names.
290 122 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
291 125 storres
    ccReducedPolynomialsList = \
292 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
293 125 storres
                                                     alpha,
294 125 storres
                                                     N,
295 125 storres
                                                     iBound,
296 125 storres
                                                     tBound)
297 125 storres
    if len(ccReducedPolynomialsList) == 0:
298 125 storres
        return set()
299 122 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
300 122 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
301 122 storres
    # Try to mix and match all the polynomial pairs built from the
302 122 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
303 122 storres
    resultantsInITuplesList = []
304 122 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
305 122 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
306 122 storres
                                     len(ccReducedPolynomialsList)):
307 122 storres
            # Compute the resultant in resultants in the
308 122 storres
            # first variable (is it the optimal choice?).
309 122 storres
            resultantInI = \
310 122 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
311 122 storres
                                                                  ccReducedPolynomialsList[0].parent(str(iVariable)))
312 122 storres
            #print "Resultant", resultantInI
313 122 storres
            # Test algebraic independence.
314 122 storres
            if not resultantInI.is_zero():
315 122 storres
                resultantsInITuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
316 122 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
317 122 storres
                                                 resultantInI))
318 122 storres
    # If no non zero resultant was found: we can't get no algebraically
319 122 storres
    # independent polynomials pair. Give up!
320 122 storres
    if len(resultantsInITuplesList) == 0:
321 123 storres
        return set()
322 123 storres
    #print resultantsInITuplesList
323 122 storres
    # Compute the roots.
324 122 storres
    Zi = ZZ[str(iVariable)]
325 122 storres
    Zt = ZZ[str(tVariable)]
326 122 storres
    polynomialRootsSet = set()
327 122 storres
    # First, solve in the second variable since resultants are in the first
328 122 storres
    # variable.
329 122 storres
    for resultantInITuple in resultantsInITuplesList:
330 122 storres
        tRootsList = Zt(resultantInITuple[2]).roots()
331 122 storres
        # For each tRoot, compute the corresponding iRoots and check
332 123 storres
        # them in the input polynomial.
333 122 storres
        for tRoot in tRootsList:
334 123 storres
            #print "tRoot:", tRoot
335 122 storres
            # Roots returned by root() are (value, multiplicity) tuples.
336 122 storres
            iRootsList = \
337 122 storres
                Zi(resultantInITuple[0].subs({resultantInITuple[0].variables()[1]:tRoot[0]})).roots()
338 123 storres
            print iRootsList
339 122 storres
            # The iRootsList can be empty, hence the test.
340 122 storres
            if len(iRootsList) != 0:
341 122 storres
                for iRoot in iRootsList:
342 122 storres
                    polyEvalModN = inputPolynomial(iRoot[0], tRoot[0]) / N
343 122 storres
                    # polyEvalModN must be an integer.
344 122 storres
                    if polyEvalModN == int(polyEvalModN):
345 122 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
346 122 storres
    return polynomialRootsSet
347 122 storres
# End slz_compute_integer_polynomial_modular_roots.
348 122 storres
#
349 125 storres
def slz_compute_integer_polynomial_modular_roots_2(inputPolynomial,
350 125 storres
                                                 alpha,
351 125 storres
                                                 N,
352 125 storres
                                                 iBound,
353 125 storres
                                                 tBound):
354 125 storres
    """
355 125 storres
    For a given set of arguments (see below), compute the polynomial modular
356 125 storres
    roots, if any.
357 125 storres
    This version differs in the way resultants are computed.
358 125 storres
    """
359 125 storres
    # Arguments check.
360 125 storres
    if iBound == 0 or tBound == 0:
361 125 storres
        return set()
362 125 storres
    # End arguments check.
363 125 storres
    nAtAlpha = N^alpha
364 125 storres
    ## Building polynomials for matrix.
365 125 storres
    polyRing   = inputPolynomial.parent()
366 125 storres
    # Whatever the 2 variables are actually called, we call them
367 125 storres
    # 'i' and 't' in all the variable names.
368 125 storres
    (iVariable, tVariable) = inputPolynomial.variables()[:2]
369 125 storres
    #print polyVars[0], type(polyVars[0])
370 125 storres
    ccReducedPolynomialsList = \
371 125 storres
        slz_compute_coppersmith_reduced_polynomials (inputPolynomial,
372 125 storres
                                                     alpha,
373 125 storres
                                                     N,
374 125 storres
                                                     iBound,
375 125 storres
                                                     tBound)
376 125 storres
    if len(ccReducedPolynomialsList) == 0:
377 125 storres
        return set()
378 125 storres
    ## Create the valid (poly1 and poly2 are algebraically independent)
379 125 storres
    # resultant tuples (poly1, poly2, resultant(poly1, poly2)).
380 125 storres
    # Try to mix and match all the polynomial pairs built from the
381 125 storres
    # ccReducedPolynomialsList to obtain non zero resultants.
382 125 storres
    resultantsInTTuplesList = []
383 125 storres
    for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList)-1):
384 125 storres
        for polyInnerIndex in xrange(polyOuterIndex+1,
385 125 storres
                                     len(ccReducedPolynomialsList)):
386 125 storres
            # Compute the resultant in resultants in the
387 125 storres
            # first variable (is it the optimal choice?).
388 125 storres
            resultantInT = \
389 125 storres
               ccReducedPolynomialsList[polyOuterIndex].resultant(ccReducedPolynomialsList[polyInnerIndex],
390 125 storres
                                                                  ccReducedPolynomialsList[0].parent(str(tVariable)))
391 125 storres
            #print "Resultant", resultantInT
392 125 storres
            # Test algebraic independence.
393 125 storres
            if not resultantInT.is_zero():
394 125 storres
                resultantsInTTuplesList.append((ccReducedPolynomialsList[polyOuterIndex],
395 125 storres
                                                 ccReducedPolynomialsList[polyInnerIndex],
396 125 storres
                                                 resultantInT))
397 125 storres
    # If no non zero resultant was found: we can't get no algebraically
398 125 storres
    # independent polynomials pair. Give up!
399 125 storres
    if len(resultantsInTTuplesList) == 0:
400 125 storres
        return set()
401 125 storres
    #print resultantsInITuplesList
402 125 storres
    # Compute the roots.
403 125 storres
    Zi = ZZ[str(iVariable)]
404 125 storres
    Zt = ZZ[str(tVariable)]
405 125 storres
    polynomialRootsSet = set()
406 125 storres
    # First, solve in the second variable since resultants are in the first
407 125 storres
    # variable.
408 125 storres
    for resultantInTTuple in resultantsInTTuplesList:
409 125 storres
        iRootsList = Zi(resultantInTTuple[2]).roots()
410 125 storres
        # For each iRoot, compute the corresponding tRoots and check
411 125 storres
        # them in the input polynomial.
412 125 storres
        for iRoot in iRootsList:
413 125 storres
            #print "iRoot:", iRoot
414 125 storres
            # Roots returned by root() are (value, multiplicity) tuples.
415 125 storres
            tRootsList = \
416 125 storres
                Zt(resultantInTTuple[0].subs({resultantInTTuple[0].variables()[0]:iRoot[0]})).roots()
417 125 storres
            print tRootsList
418 125 storres
            # The tRootsList can be empty, hence the test.
419 125 storres
            if len(tRootsList) != 0:
420 125 storres
                for tRoot in tRootsList:
421 125 storres
                    polyEvalModN = inputPolynomial(iRoot[0],tRoot[0]) / N
422 125 storres
                    # polyEvalModN must be an integer.
423 125 storres
                    if polyEvalModN == int(polyEvalModN):
424 125 storres
                        polynomialRootsSet.add((iRoot[0],tRoot[0]))
425 125 storres
    return polynomialRootsSet
426 125 storres
# End slz_compute_integer_polynomial_modular_roots_2.
427 125 storres
#
428 61 storres
def slz_compute_polynomial_and_interval(functionSo, degreeSo, lowerBoundSa,
429 61 storres
                                        upperBoundSa, approxPrecSa,
430 61 storres
                                        sollyaPrecSa=None):
431 61 storres
    """
432 61 storres
    Under the assumptions listed for slz_get_intervals_and_polynomials, compute
433 61 storres
    a polynomial that approximates the function on a an interval starting
434 61 storres
    at lowerBoundSa and finishing at a value that guarantees that the polynomial
435 61 storres
    approximates with the expected precision.
436 61 storres
    The interval upper bound is lowered until the expected approximation
437 61 storres
    precision is reached.
438 61 storres
    The polynomial, the bounds, the center of the interval and the error
439 61 storres
    are returned.
440 124 storres
    OUTPU:
441 124 storres
    A tuple made of 4 Sollya objects:
442 124 storres
    - a polynomial;
443 124 storres
    - an range (an interval, not in the sense of number given as an interval);
444 124 storres
    - the center of the interval;
445 124 storres
    - the maximum error in the approximation of the input functionSo by the
446 124 storres
      output polynomial ; this error <= approxPrecSaS.
447 124 storres
448 61 storres
    """
449 61 storres
    RRR = lowerBoundSa.parent()
450 61 storres
    intervalShrinkConstFactorSa = RRR('0.5')
451 61 storres
    absoluteErrorTypeSo = pobyso_absolute_so_so()
452 61 storres
    currentRangeSo = pobyso_bounds_to_range_sa_so(lowerBoundSa, upperBoundSa)
453 61 storres
    currentUpperBoundSa = upperBoundSa
454 61 storres
    currentLowerBoundSa = lowerBoundSa
455 61 storres
    # What we want here is the polynomial without the variable change,
456 61 storres
    # since our actual variable will be x-intervalCenter defined over the
457 61 storres
    # domain [lowerBound-intervalCenter , upperBound-intervalCenter].
458 61 storres
    (polySo, intervalCenterSo, maxErrorSo) = \
459 61 storres
        pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
460 61 storres
                                                    currentRangeSo,
461 61 storres
                                                    absoluteErrorTypeSo)
462 61 storres
    maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
463 61 storres
    while maxErrorSa > approxPrecSa:
464 101 storres
        #print "++Approximation error:", maxErrorSa
465 81 storres
        sollya_lib_clear_obj(polySo)
466 81 storres
        sollya_lib_clear_obj(intervalCenterSo)
467 120 storres
        sollya_lib_clear_obj(maxErrorSo)
468 101 storres
        shrinkFactorSa = RRR('5')/(maxErrorSa/approxPrecSa).log2().abs()
469 81 storres
        #shrinkFactorSa = 1.5/(maxErrorSa/approxPrecSa)
470 81 storres
        #errorRatioSa = approxPrecSa/maxErrorSa
471 61 storres
        #print "Error ratio: ", errorRatioSa
472 81 storres
        if shrinkFactorSa > intervalShrinkConstFactorSa:
473 81 storres
            actualShrinkFactorSa = intervalShrinkConstFactorSa
474 81 storres
            #print "Fixed"
475 61 storres
        else:
476 81 storres
            actualShrinkFactorSa = shrinkFactorSa
477 81 storres
            #print "Computed",shrinkFactorSa,maxErrorSa
478 81 storres
            #print shrinkFactorSa, maxErrorSa
479 101 storres
        #print "Shrink factor", actualShrinkFactorSa
480 81 storres
        currentUpperBoundSa = currentLowerBoundSa + \
481 61 storres
                                  (currentUpperBoundSa - currentLowerBoundSa) * \
482 81 storres
                                   actualShrinkFactorSa
483 71 storres
        #print "Current upper bound:", currentUpperBoundSa
484 61 storres
        sollya_lib_clear_obj(currentRangeSo)
485 101 storres
        if currentUpperBoundSa <= currentLowerBoundSa or \
486 101 storres
              currentUpperBoundSa == currentLowerBoundSa.nextabove():
487 86 storres
            sollya_lib_clear_obj(absoluteErrorTypeSo)
488 86 storres
            print "Can't find an interval."
489 86 storres
            print "Use either or both a higher polynomial degree or a higher",
490 86 storres
            print "internal precision."
491 86 storres
            print "Aborting!"
492 86 storres
            return (None, None, None, None)
493 61 storres
        currentRangeSo = pobyso_bounds_to_range_sa_so(currentLowerBoundSa,
494 61 storres
                                                      currentUpperBoundSa)
495 86 storres
        # print "New interval:",
496 86 storres
        # pobyso_autoprint(currentRangeSo)
497 120 storres
        #print "Second Taylor expansion call."
498 61 storres
        (polySo, intervalCenterSo, maxErrorSo) = \
499 61 storres
            pobyso_taylor_expansion_no_change_var_so_so(functionSo, degreeSo,
500 61 storres
                                                        currentRangeSo,
501 61 storres
                                                        absoluteErrorTypeSo)
502 61 storres
        #maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo, RRR)
503 85 storres
        #print "Max errorSo:",
504 85 storres
        #pobyso_autoprint(maxErrorSo)
505 61 storres
        maxErrorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
506 85 storres
        #print "Max errorSa:", maxErrorSa
507 85 storres
        #print "Sollya prec:",
508 85 storres
        #pobyso_autoprint(sollya_lib_get_prec(None))
509 61 storres
    sollya_lib_clear_obj(absoluteErrorTypeSo)
510 61 storres
    return((polySo, currentRangeSo, intervalCenterSo, maxErrorSo))
511 81 storres
# End slz_compute_polynomial_and_interval
512 61 storres
513 122 storres
def slz_compute_reduced_polynomial(matrixRow,
514 98 storres
                                    knownMonomials,
515 106 storres
                                    var1,
516 98 storres
                                    var1Bound,
517 106 storres
                                    var2,
518 99 storres
                                    var2Bound):
519 98 storres
    """
520 125 storres
    Compute a polynomial from a single reduced matrix row.
521 122 storres
    This function was introduced in order to avoid the computation of the
522 125 storres
    all the polynomials  from the full matrix (even those built from rows
523 125 storres
    that do no verify the Coppersmith condition) as this may involves
524 125 storres
    expensive operations over (large) integer.
525 122 storres
    """
526 122 storres
    ## Check arguments.
527 122 storres
    if len(knownMonomials) == 0:
528 122 storres
        return None
529 122 storres
    # varNounds can be zero since 0^0 returns 1.
530 122 storres
    if (var1Bound < 0) or (var2Bound < 0):
531 122 storres
        return None
532 122 storres
    ## Initialisations.
533 122 storres
    polynomialRing = knownMonomials[0].parent()
534 122 storres
    currentPolynomial = polynomialRing(0)
535 123 storres
    # TODO: use zip instead of indices.
536 122 storres
    for colIndex in xrange(0, len(knownMonomials)):
537 122 storres
        currentCoefficient = matrixRow[colIndex]
538 122 storres
        if currentCoefficient != 0:
539 122 storres
            #print "Current coefficient:", currentCoefficient
540 122 storres
            currentMonomial = knownMonomials[colIndex]
541 122 storres
            #print "Monomial as multivariate polynomial:", \
542 122 storres
            #currentMonomial, type(currentMonomial)
543 122 storres
            degreeInVar1 = currentMonomial.degree(var1)
544 123 storres
            #print "Degree in var1", var1, ":", degreeInVar1
545 122 storres
            degreeInVar2 = currentMonomial.degree(var2)
546 123 storres
            #print "Degree in var2", var2, ":", degreeInVar2
547 122 storres
            if degreeInVar1 > 0:
548 122 storres
                currentCoefficient = \
549 123 storres
                    currentCoefficient / (var1Bound^degreeInVar1)
550 122 storres
                #print "varBound1 in degree:", var1Bound^degreeInVar1
551 122 storres
                #print "Current coefficient(1)", currentCoefficient
552 122 storres
            if degreeInVar2 > 0:
553 122 storres
                currentCoefficient = \
554 123 storres
                    currentCoefficient / (var2Bound^degreeInVar2)
555 122 storres
                #print "Current coefficient(2)", currentCoefficient
556 122 storres
            #print "Current reduced monomial:", (currentCoefficient * \
557 122 storres
            #                                    currentMonomial)
558 122 storres
            currentPolynomial += (currentCoefficient * currentMonomial)
559 122 storres
            #print "Current polynomial:", currentPolynomial
560 122 storres
        # End if
561 122 storres
    # End for colIndex.
562 122 storres
    #print "Type of the current polynomial:", type(currentPolynomial)
563 122 storres
    return(currentPolynomial)
564 122 storres
# End slz_compute_reduced_polynomial
565 122 storres
#
566 122 storres
def slz_compute_reduced_polynomials(reducedMatrix,
567 122 storres
                                        knownMonomials,
568 122 storres
                                        var1,
569 122 storres
                                        var1Bound,
570 122 storres
                                        var2,
571 122 storres
                                        var2Bound):
572 122 storres
    """
573 122 storres
    Legacy function, use slz_compute_reduced_polynomials_list
574 122 storres
    """
575 122 storres
    return(slz_compute_reduced_polynomials_list(reducedMatrix,
576 122 storres
                                                knownMonomials,
577 122 storres
                                                var1,
578 122 storres
                                                var1Bound,
579 122 storres
                                                var2,
580 122 storres
                                                var2Bound)
581 122 storres
    )
582 122 storres
def slz_compute_reduced_polynomials_list(reducedMatrix,
583 122 storres
                                        knownMonomials,
584 122 storres
                                        var1,
585 122 storres
                                        var1Bound,
586 122 storres
                                        var2,
587 122 storres
                                        var2Bound):
588 122 storres
    """
589 98 storres
    From a reduced matrix, holding the coefficients, from a monomials list,
590 98 storres
    from the bounds of each variable, compute the corresponding polynomials
591 98 storres
    scaled back by dividing by the "right" powers of the variables bounds.
592 99 storres
593 99 storres
    The elements in knownMonomials must be of the "right" polynomial type.
594 103 storres
    They set the polynomial type of the output polynomials list.
595 98 storres
    """
596 99 storres
597 98 storres
    # TODO: check input arguments.
598 98 storres
    reducedPolynomials = []
599 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
600 98 storres
    for matrixRow in reducedMatrix.rows():
601 102 storres
        currentPolynomial = 0
602 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
603 98 storres
            currentCoefficient = matrixRow[colIndex]
604 106 storres
            if currentCoefficient != 0:
605 106 storres
                #print "Current coefficient:", currentCoefficient
606 106 storres
                currentMonomial = knownMonomials[colIndex]
607 106 storres
                parentRing = currentMonomial.parent()
608 106 storres
                #print "Monomial as multivariate polynomial:", \
609 106 storres
                #currentMonomial, type(currentMonomial)
610 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
611 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
612 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
613 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
614 106 storres
                if degreeInVar1 > 0:
615 106 storres
                    currentCoefficient = \
616 106 storres
                        currentCoefficient / var1Bound^degreeInVar1
617 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
618 106 storres
                    #print "Current coefficient(1)", currentCoefficient
619 106 storres
                if degreeInVar2 > 0:
620 106 storres
                    currentCoefficient = \
621 106 storres
                        currentCoefficient / var2Bound^degreeInVar2
622 106 storres
                    #print "Current coefficient(2)", currentCoefficient
623 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
624 106 storres
                #                                    currentMonomial)
625 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
626 106 storres
                #print "Current polynomial:", currentPolynomial
627 106 storres
            # End if
628 106 storres
        # End for colIndex.
629 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
630 99 storres
        reducedPolynomials.append(currentPolynomial)
631 98 storres
    return reducedPolynomials
632 99 storres
# End slz_compute_reduced_polynomials.
633 98 storres
634 114 storres
def slz_compute_scaled_function(functionSa,
635 114 storres
                                lowerBoundSa,
636 114 storres
                                upperBoundSa,
637 114 storres
                                floatingPointPrecSa):
638 72 storres
    """
639 72 storres
    From a function, compute the scaled function whose domain
640 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
641 72 storres
    Return a tuple:
642 72 storres
    [0]: the scaled function
643 72 storres
    [1]: the scaled domain lower bound
644 72 storres
    [2]: the scaled domain upper bound
645 72 storres
    [3]: the scaled image lower bound
646 72 storres
    [4]: the scaled image upper bound
647 72 storres
    """
648 80 storres
    x = functionSa.variables()[0]
649 80 storres
    # Reassert f as a function (an not a mere expression).
650 80 storres
651 72 storres
    # Scalling the domain -> [1,2[.
652 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
653 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
654 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
655 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
656 72 storres
    print "domainScalingExpression for argument :", domainScalingExpressionSa
657 72 storres
    print "f: ", f
658 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
659 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
660 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
661 80 storres
    scaledLowerBoundSa = domainScalingFunction(lowerBoundSa).n()
662 80 storres
    scaledUpperBoundSa = domainScalingFunction(upperBoundSa).n()
663 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
664 72 storres
    #
665 72 storres
    # Scalling the image -> [1,2[.
666 72 storres
    flbSa = f(lowerBoundSa).n()
667 72 storres
    fubSa = f(upperBoundSa).n()
668 72 storres
    if flbSa <= fubSa: # Increasing
669 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
670 72 storres
    else: # Decreasing
671 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
672 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
673 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
674 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
675 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
676 72 storres
    iis = invImageScalingExpressionSa.function(x)
677 72 storres
    fff = iis.subs({x:ff})
678 72 storres
    print "fff:", fff,
679 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
680 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
681 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
682 72 storres
683 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
684 79 storres
    # Create a polynomial over the rationals.
685 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
686 79 storres
    return(polynomialRing(polyOfFloat))
687 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
688 81 storres
689 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
690 63 storres
                                      lowerBoundSa,
691 60 storres
                                      upperBoundSa, floatingPointPrecSa,
692 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
693 60 storres
    """
694 60 storres
    Under the assumption that:
695 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
696 60 storres
    - lowerBound and upperBound belong to the same binade.
697 60 storres
    from a:
698 60 storres
    - function;
699 60 storres
    - a degree
700 60 storres
    - a pair of bounds;
701 60 storres
    - the floating-point precision we work on;
702 60 storres
    - the internal Sollya precision;
703 64 storres
    - the requested approximation error
704 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
705 61 storres
    It return a list of tuples, each made of:
706 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
707 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
708 61 storres
    - the approximation interval;
709 72 storres
    - the center, x0, of the interval;
710 61 storres
    - the corresponding approximation error.
711 100 storres
    TODO: fix endless looping for some parameters sets.
712 60 storres
    """
713 120 storres
    resultArray = []
714 101 storres
    # Set Sollya to the necessary internal precision.
715 120 storres
    precChangedSa = False
716 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
717 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
718 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
719 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
720 120 storres
        precChangedSa = True
721 101 storres
    #
722 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
723 101 storres
    # Scaled function: [1=,2] -> [1,2].
724 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
725 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
726 115 storres
                slz_compute_scaled_function(functionSa,                       \
727 115 storres
                                            lowerBoundSa,                     \
728 115 storres
                                            upperBoundSa,                     \
729 80 storres
                                            floatingPointPrecSa)
730 60 storres
    #
731 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
732 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
733 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
734 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
735 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
736 61 storres
                                                  scaledUpperBoundSa)
737 61 storres
    # Compute the first Taylor expansion.
738 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
739 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
740 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
741 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
742 86 storres
    if polySo is None:
743 101 storres
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
744 120 storres
        if precChangedSa:
745 120 storres
            pobyso_set_prec_so_so(currentSollyaPrecSo)
746 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
747 115 storres
        sollya_lib_clear_obj(functionSo)
748 115 storres
        sollya_lib_clear_obj(degreeSo)
749 115 storres
        sollya_lib_clear_obj(scaledBoundsSo)
750 86 storres
        return None
751 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
752 60 storres
                                              upperBoundSa.parent().precision()))
753 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
754 101 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
755 101 storres
    #print "First approximation error:", errorSa
756 101 storres
    # If the error and interval are OK a the first try, just return.
757 101 storres
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
758 101 storres
        # Change variable stuff in Sollya x -> x0-x.
759 101 storres
        changeVarExpressionSo = sollya_lib_build_function_sub( \
760 101 storres
                              sollya_lib_build_function_free_variable(), \
761 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
762 101 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
763 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
764 101 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
765 101 storres
                            intervalCenterSo, maxErrorSo))
766 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
767 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
768 115 storres
        sollya_lib_clear_obj(currentSollyaPrecSo)
769 101 storres
        sollya_lib_clear_obj(functionSo)
770 101 storres
        sollya_lib_clear_obj(degreeSo)
771 101 storres
        sollya_lib_clear_obj(scaledBoundsSo)
772 101 storres
        #print "Approximation error:", errorSa
773 101 storres
        return resultArray
774 120 storres
    # The returned interval upper bound does not reach the requested upper
775 120 storres
    # upper bound: compute the next upper bound.
776 101 storres
    # The following ratio is always >= 1
777 81 storres
    currentErrorRatio = approxPrecSa / errorSa
778 101 storres
    # Starting point for the next upper bound.
779 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
780 101 storres
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
781 101 storres
    # Compute the increment.
782 101 storres
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
783 81 storres
        currentScaledUpperBoundSa += \
784 101 storres
                        currentErrorRatio * boundsWidthSa * 2
785 101 storres
    else:  # [1, 1.5]
786 81 storres
        currentScaledUpperBoundSa += \
787 101 storres
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
788 101 storres
    # Take into account the original interval upper bound.
789 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
790 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
791 61 storres
    # Compute the other expansions.
792 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
793 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
794 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
795 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
796 60 storres
                                            currentScaledLowerBoundSa,
797 81 storres
                                            currentScaledUpperBoundSa,
798 81 storres
                                            approxPrecSa,
799 60 storres
                                            internalSollyaPrecSa)
800 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
801 101 storres
        if  errorSa < approxPrecSa:
802 101 storres
            # Change variable stuff
803 101 storres
            #print "Approximation error:", errorSa
804 101 storres
            changeVarExpressionSo = sollya_lib_build_function_sub(
805 101 storres
                                    sollya_lib_build_function_free_variable(),
806 101 storres
                                    sollya_lib_copy_obj(intervalCenterSo))
807 101 storres
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
808 115 storres
            sollya_lib_clear_obj(changeVarExpressionSo)
809 101 storres
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
810 101 storres
                                intervalCenterSo, maxErrorSo))
811 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
812 81 storres
        # Compute the next upper bound.
813 101 storres
        # The following ratio is always >= 1
814 81 storres
        currentErrorRatio = approxPrecSa / errorSa
815 101 storres
        # Starting point for the next upper bound.
816 101 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
817 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
818 101 storres
        # Compute the increment.
819 101 storres
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
820 101 storres
            currentScaledUpperBoundSa += \
821 101 storres
                            currentErrorRatio * boundsWidthSa * 2
822 101 storres
        else:  # [1, 1.5]
823 101 storres
            currentScaledUpperBoundSa += \
824 101 storres
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
825 101 storres
        #print "currentErrorRatio:", currentErrorRatio
826 101 storres
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
827 85 storres
        # Test for insufficient precision.
828 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
829 85 storres
            print "Can't shrink the interval anymore!"
830 85 storres
            print "You should consider increasing the Sollya internal precision"
831 85 storres
            print "or the polynomial degree."
832 85 storres
            print "Giving up!"
833 101 storres
            if internalSollyaPrecSa != currentSollyaPrecSa:
834 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
835 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
836 85 storres
            sollya_lib_clear_obj(functionSo)
837 85 storres
            sollya_lib_clear_obj(degreeSo)
838 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
839 85 storres
            return None
840 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
841 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
842 115 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
843 115 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
844 115 storres
    sollya_lib_clear_obj(currentSollyaPrecSo)
845 60 storres
    sollya_lib_clear_obj(functionSo)
846 60 storres
    sollya_lib_clear_obj(degreeSo)
847 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
848 60 storres
    return(resultArray)
849 81 storres
# End slz_get_intervals_and_polynomials
850 60 storres
851 81 storres
852 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
853 61 storres
    """
854 114 storres
    Compute the scaling expression to map an interval that span at most
855 114 storres
    a single binade to [1, 2) and the inverse expression as well.
856 62 storres
    Not very sure that the transformation makes sense for negative numbers.
857 61 storres
    """
858 62 storres
    # The scaling offset is only used for negative numbers.
859 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
860 61 storres
        if boundsInterval.endpoints()[0] >= 0:
861 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
862 62 storres
            invScalingCoeff = 1/scalingCoeff
863 80 storres
            return((scalingCoeff * expVar,
864 80 storres
                    invScalingCoeff * expVar))
865 60 storres
        else:
866 62 storres
            scalingCoeff = \
867 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
868 62 storres
            scalingOffset = -3 * scalingCoeff
869 80 storres
            return((scalingCoeff * expVar + scalingOffset,
870 80 storres
                    1/scalingCoeff * expVar + 3))
871 61 storres
    else:
872 61 storres
        if boundsInterval.endpoints()[0] >= 0:
873 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
874 61 storres
            scalingOffset = 0
875 80 storres
            return((scalingCoeff * expVar,
876 80 storres
                    1/scalingCoeff * expVar))
877 61 storres
        else:
878 62 storres
            scalingCoeff = \
879 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
880 62 storres
            scalingOffset =  -3 * scalingCoeff
881 62 storres
            #scalingOffset = 0
882 80 storres
            return((scalingCoeff * expVar + scalingOffset,
883 80 storres
                    1/scalingCoeff * expVar + 3))
884 61 storres
885 61 storres
886 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
887 72 storres
    """
888 72 storres
    Compute the Sage version of the Taylor polynomial and it's
889 72 storres
    companion data (interval, center...)
890 72 storres
    The input parameter is a five elements tuple:
891 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
892 79 storres
           real ring;
893 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
894 79 storres
           over a real ring;
895 72 storres
    - [2]: the interval (as Sollya range);
896 72 storres
    - [3]: the interval center;
897 72 storres
    - [4]: the approximation error.
898 72 storres
899 72 storres
    The function return a 5 elements tuple: formed with all the
900 72 storres
    input elements converted into their Sollya counterpart.
901 72 storres
    """
902 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
903 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
904 60 storres
    intervalSa = \
905 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
906 60 storres
    centerSa = \
907 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
908 60 storres
    errorSa = \
909 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
910 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
911 83 storres
    # End slz_interval_and_polynomial_to_sage
912 62 storres
913 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
914 80 storres
                                                precision,
915 80 storres
                                                targetHardnessToRound,
916 80 storres
                                                variable1,
917 80 storres
                                                variable2):
918 80 storres
    """
919 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
920 90 storres
     with the Coppersmith method.
921 80 storres
    A the same time it computes :
922 80 storres
    - 2^K (N);
923 90 storres
    - 2^k (bound on the second variable)
924 80 storres
    - lcm
925 90 storres
926 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
927 90 storres
                         variables.
928 90 storres
    :param precision: the precision of the floating-point coefficients.
929 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
930 90 storres
    :param variable1: the first variable of the polynomial (an expression).
931 90 storres
    :param variable2: the second variable of the polynomial (an expression).
932 90 storres
933 90 storres
    :returns: a 4 elements tuple:
934 90 storres
                - the polynomial;
935 91 storres
                - the modulus (N);
936 91 storres
                - the t bound;
937 90 storres
                - the lcm used to compute the integral coefficients and the
938 90 storres
                  module.
939 80 storres
    """
940 80 storres
    # Create a new integer polynomial ring.
941 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
942 80 storres
    # Coefficients are issued in the increasing power order.
943 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
944 91 storres
    # Print the reversed list for debugging.
945 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
946 94 storres
    # Build the list of number we compute the lcm of.
947 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
948 80 storres
    coefficientDenominators.append(2^precision)
949 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
950 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
951 80 storres
    # Compute the expression corresponding to the new polynomial
952 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
953 91 storres
    #print coefficientNumerators
954 80 storres
    polynomialExpression = 0
955 80 storres
    power = 0
956 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
957 80 storres
    # exhausted.
958 80 storres
    for numerator, denominator in \
959 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
960 80 storres
        multiplicator = leastCommonMultiple / denominator
961 80 storres
        newCoefficient = numerator * multiplicator
962 80 storres
        polynomialExpression += newCoefficient * variable1^power
963 80 storres
        power +=1
964 80 storres
    polynomialExpression += - variable2
965 80 storres
    return (IP(polynomialExpression),
966 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
967 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
968 91 storres
            leastCommonMultiple) # If we want to make test computations.
969 80 storres
970 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
971 79 storres
972 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
973 79 storres
                                          precision):
974 79 storres
    """
975 79 storres
    Makes a variable substitution into the input polynomial so that the output
976 79 storres
    polynomial can take integer arguments.
977 79 storres
    All variables of the input polynomial "have precision p". That is to say
978 103 storres
    that they are rationals with denominator == 2^(precision - 1):
979 103 storres
    x = y/2^(precision - 1).
980 79 storres
    We "incorporate" these denominators into the coefficients with,
981 79 storres
    respectively, the "right" power.
982 79 storres
    """
983 79 storres
    polynomialField = ratPolyOfRat.parent()
984 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
985 91 storres
    #print "The polynomial field is:", polynomialField
986 79 storres
    return \
987 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
988 79 storres
                                   polynomialVariable/2^(precision-1)}))
989 79 storres
990 79 storres
    # Return a tuple:
991 79 storres
    # - the bivariate integer polynomial in (i,j);
992 79 storres
    # - 2^K
993 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
994 79 storres
995 115 storres
996 87 storres
print "\t...sageSLZ loaded"
997 122 storres
print