Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (46,69 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 152 storres
    expensive operations over (large) integers.
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 152 storres
                                         knownMonomials,
584 152 storres
                                         var1,
585 152 storres
                                         var1Bound,
586 152 storres
                                         var2,
587 152 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 152 storres
    @param reducedMatrix:  the reduced matrix as output from LLL;
596 152 storres
    @param kwnonMonomials: the ordered list of the monomials used to
597 152 storres
                           build the polynomials;
598 152 storres
    @param var1:           the first variable (of the "right" type);
599 152 storres
    @param var1Bound:      the first variable bound;
600 152 storres
    @param var2:           the second variable (of the "right" type);
601 152 storres
    @param var2Bound:      the second variable bound.
602 152 storres
    @return: a list of polynomials obtained with the reduced coefficients
603 152 storres
             and scaled down with the bounds
604 98 storres
    """
605 99 storres
606 98 storres
    # TODO: check input arguments.
607 98 storres
    reducedPolynomials = []
608 106 storres
    #print "type var1:", type(var1), " - type var2:", type(var2)
609 98 storres
    for matrixRow in reducedMatrix.rows():
610 102 storres
        currentPolynomial = 0
611 98 storres
        for colIndex in xrange(0, len(knownMonomials)):
612 98 storres
            currentCoefficient = matrixRow[colIndex]
613 106 storres
            if currentCoefficient != 0:
614 106 storres
                #print "Current coefficient:", currentCoefficient
615 106 storres
                currentMonomial = knownMonomials[colIndex]
616 106 storres
                parentRing = currentMonomial.parent()
617 106 storres
                #print "Monomial as multivariate polynomial:", \
618 106 storres
                #currentMonomial, type(currentMonomial)
619 106 storres
                degreeInVar1 = currentMonomial.degree(parentRing(var1))
620 106 storres
                #print "Degree in var", var1, ":", degreeInVar1
621 106 storres
                degreeInVar2 = currentMonomial.degree(parentRing(var2))
622 106 storres
                #print "Degree in var", var2, ":", degreeInVar2
623 106 storres
                if degreeInVar1 > 0:
624 106 storres
                    currentCoefficient = \
625 106 storres
                        currentCoefficient / var1Bound^degreeInVar1
626 106 storres
                    #print "varBound1 in degree:", var1Bound^degreeInVar1
627 106 storres
                    #print "Current coefficient(1)", currentCoefficient
628 106 storres
                if degreeInVar2 > 0:
629 106 storres
                    currentCoefficient = \
630 106 storres
                        currentCoefficient / var2Bound^degreeInVar2
631 106 storres
                    #print "Current coefficient(2)", currentCoefficient
632 106 storres
                #print "Current reduced monomial:", (currentCoefficient * \
633 106 storres
                #                                    currentMonomial)
634 106 storres
                currentPolynomial += (currentCoefficient * currentMonomial)
635 106 storres
                #print "Current polynomial:", currentPolynomial
636 106 storres
            # End if
637 106 storres
        # End for colIndex.
638 99 storres
        #print "Type of the current polynomial:", type(currentPolynomial)
639 99 storres
        reducedPolynomials.append(currentPolynomial)
640 98 storres
    return reducedPolynomials
641 99 storres
# End slz_compute_reduced_polynomials.
642 98 storres
643 114 storres
def slz_compute_scaled_function(functionSa,
644 114 storres
                                lowerBoundSa,
645 114 storres
                                upperBoundSa,
646 114 storres
                                floatingPointPrecSa):
647 72 storres
    """
648 72 storres
    From a function, compute the scaled function whose domain
649 72 storres
    is included in [1, 2) and whose image is also included in [1,2).
650 72 storres
    Return a tuple:
651 72 storres
    [0]: the scaled function
652 72 storres
    [1]: the scaled domain lower bound
653 72 storres
    [2]: the scaled domain upper bound
654 72 storres
    [3]: the scaled image lower bound
655 72 storres
    [4]: the scaled image upper bound
656 72 storres
    """
657 80 storres
    x = functionSa.variables()[0]
658 80 storres
    # Reassert f as a function (an not a mere expression).
659 80 storres
660 72 storres
    # Scalling the domain -> [1,2[.
661 72 storres
    boundsIntervalRifSa = RealIntervalField(floatingPointPrecSa)
662 72 storres
    domainBoundsIntervalSa = boundsIntervalRifSa(lowerBoundSa, upperBoundSa)
663 72 storres
    (domainScalingExpressionSa, invDomainScalingExpressionSa) = \
664 80 storres
        slz_interval_scaling_expression(domainBoundsIntervalSa, x)
665 151 storres
    print "domainScalingExpression for argument :", invDomainScalingExpressionSa
666 72 storres
    print "f: ", f
667 72 storres
    ff = f.subs({x : domainScalingExpressionSa})
668 72 storres
    #ff = f.subs_expr(x==domainScalingExpressionSa)
669 80 storres
    domainScalingFunction(x) = invDomainScalingExpressionSa
670 151 storres
    scaledLowerBoundSa = \
671 151 storres
        domainScalingFunction(lowerBoundSa).n(prec=floatingPointPrecSa)
672 151 storres
    scaledUpperBoundSa = \
673 151 storres
        domainScalingFunction(upperBoundSa).n(prec=floatingPointPrecSa)
674 72 storres
    print 'ff:', ff, "- Domain:", scaledLowerBoundSa, scaledUpperBoundSa
675 72 storres
    #
676 72 storres
    # Scalling the image -> [1,2[.
677 151 storres
    flbSa = ff(scaledLowerBoundSa).n(prec=floatingPointPrecSa)
678 151 storres
    fubSa = ff(scaledUpperBoundSa).n(prec=floatingPointPrecSa)
679 72 storres
    if flbSa <= fubSa: # Increasing
680 72 storres
        imageBinadeBottomSa = floor(flbSa.log2())
681 72 storres
    else: # Decreasing
682 72 storres
        imageBinadeBottomSa = floor(fubSa.log2())
683 72 storres
    print 'ff:', ff, '- Image:', flbSa, fubSa, imageBinadeBottomSa
684 72 storres
    imageBoundsIntervalSa = boundsIntervalRifSa(flbSa, fubSa)
685 72 storres
    (imageScalingExpressionSa, invImageScalingExpressionSa) = \
686 80 storres
        slz_interval_scaling_expression(imageBoundsIntervalSa, x)
687 151 storres
    print "imageScalingExpression for argument :", invImageScalingExpressionSa
688 72 storres
    iis = invImageScalingExpressionSa.function(x)
689 72 storres
    fff = iis.subs({x:ff})
690 72 storres
    print "fff:", fff,
691 72 storres
    print " - Image:", fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)
692 72 storres
    return([fff, scaledLowerBoundSa, scaledUpperBoundSa, \
693 72 storres
            fff(scaledLowerBoundSa), fff(scaledUpperBoundSa)])
694 151 storres
# End slz_compute_scaled_function
695 72 storres
696 79 storres
def slz_float_poly_of_float_to_rat_poly_of_rat(polyOfFloat):
697 79 storres
    # Create a polynomial over the rationals.
698 79 storres
    polynomialRing = QQ[str(polyOfFloat.variables()[0])]
699 79 storres
    return(polynomialRing(polyOfFloat))
700 86 storres
# End slz_float_poly_of_float_to_rat_poly_of_rat.
701 81 storres
702 80 storres
def slz_get_intervals_and_polynomials(functionSa, degreeSa,
703 63 storres
                                      lowerBoundSa,
704 60 storres
                                      upperBoundSa, floatingPointPrecSa,
705 64 storres
                                      internalSollyaPrecSa, approxPrecSa):
706 60 storres
    """
707 60 storres
    Under the assumption that:
708 60 storres
    - functionSa is monotonic on the [lowerBoundSa, upperBoundSa] interval;
709 60 storres
    - lowerBound and upperBound belong to the same binade.
710 60 storres
    from a:
711 60 storres
    - function;
712 60 storres
    - a degree
713 60 storres
    - a pair of bounds;
714 60 storres
    - the floating-point precision we work on;
715 60 storres
    - the internal Sollya precision;
716 64 storres
    - the requested approximation error
717 61 storres
    The initial interval is, possibly, splitted into smaller intervals.
718 61 storres
    It return a list of tuples, each made of:
719 72 storres
    - a first polynomial (without the changed variable f(x) = p(x-x0));
720 79 storres
    - a second polynomial (with a changed variable f(x) = q(x))
721 61 storres
    - the approximation interval;
722 72 storres
    - the center, x0, of the interval;
723 61 storres
    - the corresponding approximation error.
724 100 storres
    TODO: fix endless looping for some parameters sets.
725 60 storres
    """
726 120 storres
    resultArray = []
727 101 storres
    # Set Sollya to the necessary internal precision.
728 120 storres
    precChangedSa = False
729 85 storres
    currentSollyaPrecSo = pobyso_get_prec_so()
730 85 storres
    currentSollyaPrecSa = pobyso_constant_from_int_so_sa(currentSollyaPrecSo)
731 85 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
732 85 storres
        pobyso_set_prec_sa_so(internalSollyaPrecSa)
733 120 storres
        precChangedSa = True
734 101 storres
    #
735 80 storres
    x = functionSa.variables()[0] # Actual variable name can be anything.
736 101 storres
    # Scaled function: [1=,2] -> [1,2].
737 115 storres
    (fff, scaledLowerBoundSa, scaledUpperBoundSa,                             \
738 115 storres
            scaledLowerBoundImageSa, scaledUpperBoundImageSa) =               \
739 115 storres
                slz_compute_scaled_function(functionSa,                       \
740 115 storres
                                            lowerBoundSa,                     \
741 115 storres
                                            upperBoundSa,                     \
742 80 storres
                                            floatingPointPrecSa)
743 60 storres
    #
744 60 storres
    print "Approximation precision: ", RR(approxPrecSa)
745 61 storres
    # Prepare the arguments for the Taylor expansion computation with Sollya.
746 62 storres
    functionSo = pobyso_parse_string_sa_so(fff._assume_str())
747 60 storres
    degreeSo = pobyso_constant_from_int_sa_so(degreeSa)
748 61 storres
    scaledBoundsSo = pobyso_bounds_to_range_sa_so(scaledLowerBoundSa,
749 61 storres
                                                  scaledUpperBoundSa)
750 61 storres
    # Compute the first Taylor expansion.
751 60 storres
    (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
752 60 storres
        slz_compute_polynomial_and_interval(functionSo, degreeSo,
753 60 storres
                                        scaledLowerBoundSa, scaledUpperBoundSa,
754 60 storres
                                        approxPrecSa, internalSollyaPrecSa)
755 86 storres
    if polySo is None:
756 101 storres
        print "slz_get_intervals_and_polynomials: Aborting and returning None!"
757 120 storres
        if precChangedSa:
758 120 storres
            pobyso_set_prec_so_so(currentSollyaPrecSo)
759 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
760 115 storres
        sollya_lib_clear_obj(functionSo)
761 115 storres
        sollya_lib_clear_obj(degreeSo)
762 115 storres
        sollya_lib_clear_obj(scaledBoundsSo)
763 86 storres
        return None
764 60 storres
    realIntervalField = RealIntervalField(max(lowerBoundSa.parent().precision(),
765 60 storres
                                              upperBoundSa.parent().precision()))
766 61 storres
    boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
767 101 storres
    errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
768 151 storres
    print "First approximation error:", errorSa.n(digits=50)
769 101 storres
    # If the error and interval are OK a the first try, just return.
770 101 storres
    if boundsSa.endpoints()[1] >= scaledUpperBoundSa:
771 101 storres
        # Change variable stuff in Sollya x -> x0-x.
772 101 storres
        changeVarExpressionSo = sollya_lib_build_function_sub( \
773 101 storres
                              sollya_lib_build_function_free_variable(), \
774 101 storres
                              sollya_lib_copy_obj(intervalCenterSo))
775 101 storres
        polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
776 115 storres
        sollya_lib_clear_obj(changeVarExpressionSo)
777 101 storres
        resultArray.append((polySo, polyVarChangedSo, boundsSo, \
778 101 storres
                            intervalCenterSo, maxErrorSo))
779 101 storres
        if internalSollyaPrecSa != currentSollyaPrecSa:
780 101 storres
            pobyso_set_prec_sa_so(currentSollyaPrecSa)
781 115 storres
        sollya_lib_clear_obj(currentSollyaPrecSo)
782 101 storres
        sollya_lib_clear_obj(functionSo)
783 101 storres
        sollya_lib_clear_obj(degreeSo)
784 101 storres
        sollya_lib_clear_obj(scaledBoundsSo)
785 101 storres
        #print "Approximation error:", errorSa
786 101 storres
        return resultArray
787 120 storres
    # The returned interval upper bound does not reach the requested upper
788 120 storres
    # upper bound: compute the next upper bound.
789 101 storres
    # The following ratio is always >= 1
790 81 storres
    currentErrorRatio = approxPrecSa / errorSa
791 101 storres
    # Starting point for the next upper bound.
792 81 storres
    currentScaledUpperBoundSa = boundsSa.endpoints()[1]
793 101 storres
    boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
794 101 storres
    # Compute the increment.
795 101 storres
    if currentErrorRatio > RR('1000'): # ]1.5, infinity[
796 81 storres
        currentScaledUpperBoundSa += \
797 101 storres
                        currentErrorRatio * boundsWidthSa * 2
798 101 storres
    else:  # [1, 1.5]
799 81 storres
        currentScaledUpperBoundSa += \
800 101 storres
                        (RR('1.0') + currentErrorRatio.log() / 500) * boundsWidthSa
801 101 storres
    # Take into account the original interval upper bound.
802 81 storres
    if currentScaledUpperBoundSa > scaledUpperBoundSa:
803 81 storres
        currentScaledUpperBoundSa = scaledUpperBoundSa
804 61 storres
    # Compute the other expansions.
805 60 storres
    while boundsSa.endpoints()[1] < scaledUpperBoundSa:
806 60 storres
        currentScaledLowerBoundSa = boundsSa.endpoints()[1]
807 60 storres
        (polySo, boundsSo, intervalCenterSo, maxErrorSo) = \
808 60 storres
            slz_compute_polynomial_and_interval(functionSo, degreeSo,
809 60 storres
                                            currentScaledLowerBoundSa,
810 81 storres
                                            currentScaledUpperBoundSa,
811 81 storres
                                            approxPrecSa,
812 60 storres
                                            internalSollyaPrecSa)
813 101 storres
        errorSa = pobyso_get_constant_as_rn_with_rf_so_sa(maxErrorSo)
814 101 storres
        if  errorSa < approxPrecSa:
815 101 storres
            # Change variable stuff
816 101 storres
            #print "Approximation error:", errorSa
817 101 storres
            changeVarExpressionSo = sollya_lib_build_function_sub(
818 101 storres
                                    sollya_lib_build_function_free_variable(),
819 101 storres
                                    sollya_lib_copy_obj(intervalCenterSo))
820 101 storres
            polyVarChangedSo = sollya_lib_evaluate(polySo, changeVarExpressionSo)
821 115 storres
            sollya_lib_clear_obj(changeVarExpressionSo)
822 101 storres
            resultArray.append((polySo, polyVarChangedSo, boundsSo, \
823 101 storres
                                intervalCenterSo, maxErrorSo))
824 61 storres
        boundsSa = pobyso_range_to_interval_so_sa(boundsSo, realIntervalField)
825 81 storres
        # Compute the next upper bound.
826 101 storres
        # The following ratio is always >= 1
827 81 storres
        currentErrorRatio = approxPrecSa / errorSa
828 101 storres
        # Starting point for the next upper bound.
829 101 storres
        currentScaledUpperBoundSa = boundsSa.endpoints()[1]
830 101 storres
        boundsWidthSa = boundsSa.endpoints()[1] - boundsSa.endpoints()[0]
831 101 storres
        # Compute the increment.
832 101 storres
        if currentErrorRatio > RR('1000'): # ]1.5, infinity[
833 101 storres
            currentScaledUpperBoundSa += \
834 101 storres
                            currentErrorRatio * boundsWidthSa * 2
835 101 storres
        else:  # [1, 1.5]
836 101 storres
            currentScaledUpperBoundSa += \
837 101 storres
                            (RR('1.0') + currentErrorRatio.log()/500) * boundsWidthSa
838 101 storres
        #print "currentErrorRatio:", currentErrorRatio
839 101 storres
        #print "currentScaledUpperBoundSa", currentScaledUpperBoundSa
840 85 storres
        # Test for insufficient precision.
841 85 storres
        if currentScaledUpperBoundSa == scaledLowerBoundSa:
842 85 storres
            print "Can't shrink the interval anymore!"
843 85 storres
            print "You should consider increasing the Sollya internal precision"
844 85 storres
            print "or the polynomial degree."
845 85 storres
            print "Giving up!"
846 101 storres
            if internalSollyaPrecSa != currentSollyaPrecSa:
847 101 storres
                pobyso_set_prec_sa_so(currentSollyaPrecSa)
848 115 storres
            sollya_lib_clear_obj(currentSollyaPrecSo)
849 85 storres
            sollya_lib_clear_obj(functionSo)
850 85 storres
            sollya_lib_clear_obj(degreeSo)
851 85 storres
            sollya_lib_clear_obj(scaledBoundsSo)
852 85 storres
            return None
853 81 storres
        if currentScaledUpperBoundSa > scaledUpperBoundSa:
854 81 storres
            currentScaledUpperBoundSa = scaledUpperBoundSa
855 115 storres
    if internalSollyaPrecSa > currentSollyaPrecSa:
856 115 storres
        pobyso_set_prec_so_so(currentSollyaPrecSo)
857 115 storres
    sollya_lib_clear_obj(currentSollyaPrecSo)
858 60 storres
    sollya_lib_clear_obj(functionSo)
859 60 storres
    sollya_lib_clear_obj(degreeSo)
860 60 storres
    sollya_lib_clear_obj(scaledBoundsSo)
861 60 storres
    return(resultArray)
862 81 storres
# End slz_get_intervals_and_polynomials
863 60 storres
864 81 storres
865 80 storres
def slz_interval_scaling_expression(boundsInterval, expVar):
866 61 storres
    """
867 151 storres
    Compute the scaling expression to map an interval that spans at most
868 114 storres
    a single binade to [1, 2) and the inverse expression as well.
869 62 storres
    Not very sure that the transformation makes sense for negative numbers.
870 61 storres
    """
871 62 storres
    # The scaling offset is only used for negative numbers.
872 151 storres
    # When the absolute value of the lower bound is < 0.
873 61 storres
    if abs(boundsInterval.endpoints()[0]) < 1:
874 61 storres
        if boundsInterval.endpoints()[0] >= 0:
875 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
876 62 storres
            invScalingCoeff = 1/scalingCoeff
877 80 storres
            return((scalingCoeff * expVar,
878 80 storres
                    invScalingCoeff * expVar))
879 60 storres
        else:
880 62 storres
            scalingCoeff = \
881 62 storres
                2^(floor((-boundsInterval.endpoints()[0]).log2()) - 1)
882 62 storres
            scalingOffset = -3 * scalingCoeff
883 80 storres
            return((scalingCoeff * expVar + scalingOffset,
884 80 storres
                    1/scalingCoeff * expVar + 3))
885 61 storres
    else:
886 61 storres
        if boundsInterval.endpoints()[0] >= 0:
887 62 storres
            scalingCoeff = 2^floor(boundsInterval.endpoints()[0].log2())
888 61 storres
            scalingOffset = 0
889 80 storres
            return((scalingCoeff * expVar,
890 80 storres
                    1/scalingCoeff * expVar))
891 61 storres
        else:
892 62 storres
            scalingCoeff = \
893 62 storres
                2^(floor((-boundsInterval.endpoints()[1]).log2()))
894 62 storres
            scalingOffset =  -3 * scalingCoeff
895 62 storres
            #scalingOffset = 0
896 80 storres
            return((scalingCoeff * expVar + scalingOffset,
897 80 storres
                    1/scalingCoeff * expVar + 3))
898 151 storres
# End slz_interval_scaling_expression
899 61 storres
900 83 storres
def slz_interval_and_polynomial_to_sage(polyRangeCenterErrorSo):
901 72 storres
    """
902 72 storres
    Compute the Sage version of the Taylor polynomial and it's
903 72 storres
    companion data (interval, center...)
904 72 storres
    The input parameter is a five elements tuple:
905 79 storres
    - [0]: the polyomial (without variable change), as polynomial over a
906 79 storres
           real ring;
907 79 storres
    - [1]: the polyomial (with variable change done in Sollya), as polynomial
908 79 storres
           over a real ring;
909 72 storres
    - [2]: the interval (as Sollya range);
910 72 storres
    - [3]: the interval center;
911 72 storres
    - [4]: the approximation error.
912 72 storres
913 72 storres
    The function return a 5 elements tuple: formed with all the
914 72 storres
    input elements converted into their Sollya counterpart.
915 72 storres
    """
916 60 storres
    polynomialSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[0])
917 64 storres
    polynomialChangedVarSa = pobyso_get_poly_so_sa(polyRangeCenterErrorSo[1])
918 60 storres
    intervalSa = \
919 64 storres
            pobyso_get_interval_from_range_so_sa(polyRangeCenterErrorSo[2])
920 60 storres
    centerSa = \
921 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[3])
922 60 storres
    errorSa = \
923 64 storres
            pobyso_get_constant_as_rn_with_rf_so_sa(polyRangeCenterErrorSo[4])
924 64 storres
    return((polynomialSa, polynomialChangedVarSa, intervalSa, centerSa, errorSa))
925 83 storres
    # End slz_interval_and_polynomial_to_sage
926 62 storres
927 80 storres
def slz_rat_poly_of_int_to_poly_for_coppersmith(ratPolyOfInt,
928 80 storres
                                                precision,
929 80 storres
                                                targetHardnessToRound,
930 80 storres
                                                variable1,
931 80 storres
                                                variable2):
932 80 storres
    """
933 90 storres
    Creates a new multivariate polynomial with integer coefficients for use
934 90 storres
     with the Coppersmith method.
935 80 storres
    A the same time it computes :
936 80 storres
    - 2^K (N);
937 90 storres
    - 2^k (bound on the second variable)
938 80 storres
    - lcm
939 90 storres
940 90 storres
    :param ratPolyOfInt: a polynomial with rational coefficients and integer
941 90 storres
                         variables.
942 90 storres
    :param precision: the precision of the floating-point coefficients.
943 90 storres
    :param targetHardnessToRound: the hardness to round we want to check.
944 90 storres
    :param variable1: the first variable of the polynomial (an expression).
945 90 storres
    :param variable2: the second variable of the polynomial (an expression).
946 90 storres
947 90 storres
    :returns: a 4 elements tuple:
948 90 storres
                - the polynomial;
949 91 storres
                - the modulus (N);
950 91 storres
                - the t bound;
951 90 storres
                - the lcm used to compute the integral coefficients and the
952 90 storres
                  module.
953 80 storres
    """
954 80 storres
    # Create a new integer polynomial ring.
955 80 storres
    IP = PolynomialRing(ZZ, name=str(variable1) + "," + str(variable2))
956 80 storres
    # Coefficients are issued in the increasing power order.
957 80 storres
    ratPolyCoefficients = ratPolyOfInt.coefficients()
958 91 storres
    # Print the reversed list for debugging.
959 94 storres
    print "Rational polynomial coefficients:", ratPolyCoefficients[::-1]
960 94 storres
    # Build the list of number we compute the lcm of.
961 80 storres
    coefficientDenominators = sro_denominators(ratPolyCoefficients)
962 80 storres
    coefficientDenominators.append(2^precision)
963 80 storres
    coefficientDenominators.append(2^(targetHardnessToRound + 1))
964 87 storres
    leastCommonMultiple = lcm(coefficientDenominators)
965 80 storres
    # Compute the expression corresponding to the new polynomial
966 80 storres
    coefficientNumerators =  sro_numerators(ratPolyCoefficients)
967 91 storres
    #print coefficientNumerators
968 80 storres
    polynomialExpression = 0
969 80 storres
    power = 0
970 80 storres
    # Iterate over two lists at the same time, stop when the shorter is
971 80 storres
    # exhausted.
972 80 storres
    for numerator, denominator in \
973 94 storres
                        zip(coefficientNumerators, coefficientDenominators):
974 80 storres
        multiplicator = leastCommonMultiple / denominator
975 80 storres
        newCoefficient = numerator * multiplicator
976 80 storres
        polynomialExpression += newCoefficient * variable1^power
977 80 storres
        power +=1
978 80 storres
    polynomialExpression += - variable2
979 80 storres
    return (IP(polynomialExpression),
980 80 storres
            leastCommonMultiple / 2^precision, # 2^K or N.
981 91 storres
            leastCommonMultiple / 2^(targetHardnessToRound + 1), # tBound
982 91 storres
            leastCommonMultiple) # If we want to make test computations.
983 80 storres
984 80 storres
# End slz_ratPoly_of_int_to_poly_for_coppersmith
985 79 storres
986 79 storres
def slz_rat_poly_of_rat_to_rat_poly_of_int(ratPolyOfRat,
987 79 storres
                                          precision):
988 79 storres
    """
989 79 storres
    Makes a variable substitution into the input polynomial so that the output
990 79 storres
    polynomial can take integer arguments.
991 79 storres
    All variables of the input polynomial "have precision p". That is to say
992 103 storres
    that they are rationals with denominator == 2^(precision - 1):
993 103 storres
    x = y/2^(precision - 1).
994 79 storres
    We "incorporate" these denominators into the coefficients with,
995 79 storres
    respectively, the "right" power.
996 79 storres
    """
997 79 storres
    polynomialField = ratPolyOfRat.parent()
998 91 storres
    polynomialVariable = ratPolyOfRat.variables()[0]
999 91 storres
    #print "The polynomial field is:", polynomialField
1000 79 storres
    return \
1001 91 storres
        polynomialField(ratPolyOfRat.subs({polynomialVariable : \
1002 79 storres
                                   polynomialVariable/2^(precision-1)}))
1003 79 storres
1004 79 storres
    # Return a tuple:
1005 79 storres
    # - the bivariate integer polynomial in (i,j);
1006 79 storres
    # - 2^K
1007 79 storres
# End slz_rat_poly_of_rat_to_rat_poly_of_int
1008 79 storres
1009 115 storres
1010 87 storres
print "\t...sageSLZ loaded"