Statistiques
| Révision :

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

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