Statistiques
| Révision :

root / pobysoPythonSage / src / sageSLZ / sageRunSLZ.sage @ 225

Historique | Voir | Annoter | Télécharger (154,71 ko)

1
r"""
2
Main SLZ algorithm body in several versions.
3

    
4
AUTHORS:
5
- S.T. (2015-10-10): initial version
6

    
7
Examples:
8
    TODO
9
"""
10
print "sageRationalOperations loading..."
11

    
12
def srs_compute_lattice_volume(inputFunction,
13
                    inputLowerBound,
14
                    inputUpperBound,
15
                    alpha,
16
                    degree,
17
                    precision,
18
                    emin,
19
                    emax,
20
                    targetHardnessToRound,
21
                    debug = False):
22
    """
23
    Changes from V2:
24
        Root search is changed:
25
            - we compute the resultants in i and in t;
26
            - we compute the roots set of each of these resultants;
27
            - we combine all the possible pairs between the two sets;
28
            - we check these pairs in polynomials for correctness.
29
    Changes from V1: 
30
        1- check for roots as soon as a resultant is computed;
31
        2- once a non null resultant is found, check for roots;
32
        3- constant resultant == no root.
33
    """
34

    
35
    if debug:
36
        print "Function                :", inputFunction
37
        print "Lower bound             :", inputLowerBound
38
        print "Upper bounds            :", inputUpperBound
39
        print "Alpha                   :", alpha
40
        print "Degree                  :", degree
41
        print "Precision               :", precision
42
        print "Emin                    :", emin
43
        print "Emax                    :", emax
44
        print "Target hardness-to-round:", targetHardnessToRound
45
        print
46
    ## Important constants.
47
    ### Stretch the interval if no error happens.
48
    noErrorIntervalStretch = 1 + 2^(-5)
49
    ### If no vector validates the Coppersmith condition, shrink the interval
50
    #   by the following factor.
51
    noCoppersmithIntervalShrink = 1/2
52
    ### If only (or at least) one vector validates the Coppersmith condition, 
53
    #   shrink the interval by the following factor.
54
    oneCoppersmithIntervalShrink = 3/4
55
    #### If only null resultants are found, shrink the interval by the 
56
    #    following factor.
57
    onlyNullResultantsShrink     = 3/4
58
    ## Structures.
59
    RRR         = RealField(precision)
60
    RRIF        = RealIntervalField(precision)
61
    ## Converting input bound into the "right" field.
62
    lowerBound = RRR(inputLowerBound)
63
    upperBound = RRR(inputUpperBound)
64
    ## Before going any further, check domain and image binade conditions.
65
    print inputFunction(1).n()
66
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
67
    if output is None:
68
        print "Invalid domain/image binades. Domain:",\
69
        lowerBound, upperBound, "Images:", \
70
        inputFunction(lowerBound), inputFunction(upperBound)
71
        raise Exception("Invalid domain/image binades.")
72
    lb = output[0] ; ub = output[1]
73
    if lb != lowerBound or ub != upperBound:
74
        print "lb:", lb, " - ub:", ub
75
        print "Invalid domain/image binades. Domain:",\
76
        lowerBound, upperBound, "Images:", \
77
        inputFunction(lowerBound), inputFunction(upperBound)
78
        raise Exception("Invalid domain/image binades.")
79
    #
80
    ## Progam initialization
81
    ### Approximation polynomial accuracy and hardness to round.
82
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
83
    polyTargetHardnessToRound = targetHardnessToRound + 1
84
    ### Significand to integer conversion ratio.
85
    toIntegerFactor           = 2^(precision-1)
86
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
87
    ### Variables and rings for polynomials and root searching.
88
    i=var('i')
89
    t=var('t')
90
    inputFunctionVariable = inputFunction.variables()[0]
91
    function = inputFunction.subs({inputFunctionVariable:i})
92
    #  Polynomial Rings over the integers, for root finding.
93
    Zi = ZZ[i]
94
    Zt = ZZ[t]
95
    Zit = ZZ[i,t]
96
    ## Number of iterations limit.
97
    maxIter = 100000
98
    #
99
    ## Compute the scaled function and the degree, in their Sollya version 
100
    #  once for all.
101
    (scaledf, sdlb, sdub, silb, siub) = \
102
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
103
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
104
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
105
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
106
    #
107
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
108
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
109
    (unscalingFunction, scalingFunction) = \
110
        slz_interval_scaling_expression(domainBoundsInterval, i)
111
    #print scalingFunction, unscalingFunction
112
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
113
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
114
    if internalSollyaPrec < 192:
115
        internalSollyaPrec = 192
116
    pobyso_set_prec_sa_so(internalSollyaPrec)
117
    print "Sollya internal precision:", internalSollyaPrec
118
    ## Some variables.
119
    ### General variables
120
    lb                  = sdlb
121
    ub                  = sdub
122
    nbw                 = 0
123
    intervalUlp         = ub.ulp()
124
    #### Will be set by slz_interval_and_polynomila_to_sage.
125
    ic                  = 0 
126
    icAsInt             = 0    # Set from ic.
127
    solutionsSet        = set()
128
    tsErrorWidth        = []
129
    csErrorVectors      = []
130
    csVectorsResultants = []
131
    floatP              = 0  # Taylor polynomial.
132
    floatPcv            = 0  # Ditto with variable change.
133
    intvl               = "" # Taylor interval
134
    terr                = 0  # Taylor error.
135
    iterCount = 0
136
    htrnSet = set()
137
    ### Timers and counters.
138
    wallTimeStart                   = 0
139
    cpuTimeStart                    = 0
140
    taylCondFailedCount             = 0
141
    coppCondFailedCount             = 0
142
    resultCondFailedCount           = 0
143
    coppCondFailed                  = False
144
    resultCondFailed                = False
145
    globalResultsList               = []
146
    basisConstructionsCount         = 0
147
    basisConstructionsFullTime      = 0
148
    basisConstructionTime           = 0
149
    reductionsCount                 = 0
150
    reductionsFullTime              = 0
151
    reductionTime                   = 0
152
    resultantsComputationsCount     = 0
153
    resultantsComputationsFullTime  = 0
154
    resultantsComputationTime       = 0
155
    rootsComputationsCount          = 0
156
    rootsComputationsFullTime       = 0
157
    rootsComputationTime            = 0
158
    print
159
    ## Global times are started here.
160
    wallTimeStart                   = walltime()
161
    cpuTimeStart                    = cputime()
162
    ## Main loop.
163
    while True:
164
        if lb >= sdub:
165
            print "Lower bound reached upper bound."
166
            break
167
        if iterCount == maxIter:
168
            print "Reached maxIter. Aborting"
169
            break
170
        iterCount += 1
171
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
172
            "log2(numbers)." 
173
        ### Compute a Sollya polynomial that will honor the Taylor condition.
174
        prceSo = slz_compute_polynomial_and_interval(scaledfSo,
175
                                                     degreeSo,
176
                                                     lb,
177
                                                     ub,
178
                                                     polyApproxAccur)
179
        ### Convert back the data into Sage space.                         
180
        (floatP, floatPcv, intvl, ic, terr) = \
181
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
182
                                                 prceSo[1], prceSo[2], 
183
                                                 prceSo[3]))
184
        intvl = RRIF(intvl)
185
        ## Clean-up Sollya stuff.
186
        for elem in prceSo:
187
            sollya_lib_clear_obj(elem)
188
        #print  floatP, floatPcv, intvl, ic, terr
189
        #print floatP
190
        #print intvl.endpoints()[0].n(), \
191
        #      ic.n(),
192
        #intvl.endpoints()[1].n()
193
        ### Check returned data.
194
        #### Is approximation error OK?
195
        if terr > polyApproxAccur:
196
            exceptionErrorMess  = \
197
                "Approximation failed - computed error:" + \
198
                str(terr) + " - target error: "
199
            exceptionErrorMess += \
200
                str(polyApproxAccur) + ". Aborting!"
201
            raise Exception(exceptionErrorMess)
202
        #### Is lower bound OK?
203
        if lb != intvl.endpoints()[0]:
204
            exceptionErrorMess =  "Wrong lower bound:" + \
205
                               str(lb) + ". Aborting!"
206
            raise Exception(exceptionErrorMess)
207
        #### Set upper bound.
208
        if ub > intvl.endpoints()[1]:
209
            ub = intvl.endpoints()[1]
210
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
211
            "log2(numbers)." 
212
            taylCondFailedCount += 1
213
        #### Is interval not degenerate?
214
        if lb >= ub:
215
            exceptionErrorMess = "Degenerate interval: " + \
216
                                "lowerBound(" + str(lb) +\
217
                                ")>= upperBound(" + str(ub) + \
218
                                "). Aborting!"
219
            raise Exception(exceptionErrorMess)
220
        #### Is interval center ok?
221
        if ic <= lb or ic >= ub:
222
            exceptionErrorMess =  "Invalid interval center for " + \
223
                                str(lb) + ',' + str(ic) + ',' +  \
224
                                str(ub) + ". Aborting!"
225
            raise Exception(exceptionErrorMess)
226
        ##### Current interval width and reset future interval width.
227
        bw = ub - lb
228
        nbw = 0
229
        icAsInt = int(ic * toIntegerFactor)
230
        #### The following ratio is always >= 1. In case we may want to
231
        #    enlarge the interval
232
        curTaylErrRat = polyApproxAccur / terr
233
        ### Make the  integral transformations.
234
        #### Bounds and interval center.
235
        intIc = int(ic * toIntegerFactor)
236
        intLb = int(lb * toIntegerFactor) - intIc
237
        intUb = int(ub * toIntegerFactor) - intIc
238
        #
239
        #### Polynomials
240
        basisConstructionTime         = cputime()
241
        ##### To a polynomial with rational coefficients with rational arguments
242
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
243
        ##### To a polynomial with rational coefficients with integer arguments
244
        ratIntP = \
245
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
246
        #####  Ultimately a multivariate polynomial with integer coefficients  
247
        #      with integer arguments.
248
        coppersmithTuple = \
249
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
250
                                                        precision, 
251
                                                        targetHardnessToRound, 
252
                                                        i, t)
253
        #### Recover Coppersmith information.
254
        intIntP = coppersmithTuple[0]
255
        N = coppersmithTuple[1]
256
        nAtAlpha = N^alpha
257
        tBound = coppersmithTuple[2]
258
        leastCommonMultiple = coppersmithTuple[3]
259
        iBound = max(abs(intLb),abs(intUb))
260
        basisConstructionsFullTime        += cputime(basisConstructionTime)
261
        basisConstructionsCount           += 1
262
        reductionTime                     = cputime()
263
        #### Compute the reduced polynomials.
264
        ccReducedPolynomialsList =  \
265
            slz_compute_coppersmith_reduced_polynomials_with_lattice_volume(intIntP, 
266
                                                        alpha, 
267
                                                        N, 
268
                                                        iBound, 
269
                                                        tBound)
270
        if ccReducedPolynomialsList is None:
271
            raise Exception("Reduction failed.")
272
        reductionsFullTime    += cputime(reductionTime)
273
        reductionsCount       += 1
274
        if len(ccReducedPolynomialsList) < 2:
275
            print "Nothing to form resultants with."
276
            print
277
            coppCondFailedCount += 1
278
            coppCondFailed = True
279
            ##### Apply a different shrink factor according to 
280
            #  the number of compliant polynomials.
281
            if len(ccReducedPolynomialsList) == 0:
282
                ub = lb + bw * noCoppersmithIntervalShrink
283
            else: # At least one compliant polynomial.
284
                ub = lb + bw * oneCoppersmithIntervalShrink
285
            if ub > sdub:
286
                ub = sdub
287
            if lb == ub:
288
                raise Exception("Cant shrink interval \
289
                anymore to get Coppersmith condition.")
290
            nbw = 0
291
            continue
292
        #### We have at least two polynomials.
293
        #    Let us try to compute resultants.
294
        #    For each resultant computed, go for the solutions.
295
        ##### Build the pairs list.
296
        polyPairsList           = []
297
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
298
            for polyInnerIndex in xrange(polyOuterIndex+1, 
299
                                         len(ccReducedPolynomialsList)):
300
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
301
                                      ccReducedPolynomialsList[polyInnerIndex]))
302
        #### Actual root search.
303
        rootsSet            = set()
304
        hasNonNullResultant = False
305
        for polyPair in polyPairsList:
306
            if hasNonNullResultant:
307
                break
308
            resultantsComputationTime   = cputime()
309
            currentResultantI = \
310
                slz_resultant(polyPair[0],
311
                              polyPair[1],
312
                              t)
313
            resultantsComputationsCount    += 1
314
            if currentResultantI is None:
315
                resultantsComputationsFullTime +=  \
316
                    cputime(resultantsComputationTime)
317
                print "Nul resultant"
318
                continue # Next polyPair.
319
            currentResultantT = \
320
                slz_resultant(polyPair[0],
321
                              polyPair[1],
322
                              i)
323
            resultantsComputationsFullTime += cputime(resultantsComputationTime)
324
            resultantsComputationsCount    += 1
325
            if currentResultantT is None:                    
326
                print "Nul resultant"
327
                continue # Next polyPair.
328
            else:
329
                hasNonNullResultant = True
330
            #### We have a non null resultants pair. From now on, whatever the
331
            #    root search yields, no extra root search is necessary.
332
            #### A constant resultant leads to no root. Root search is done.
333
            if currentResultantI.degree() < 1:
334
                print "Resultant is constant:", currentResultantI
335
                break # Next polyPair and should break.
336
            if currentResultantT.degree() < 1:
337
                print "Resultant is constant:", currentResultantT
338
                break # Next polyPair and should break.
339
            #### Actual roots computation.
340
            rootsComputationTime       = cputime()
341
            ##### Compute i roots
342
            iRootsList = Zi(currentResultantI).roots()
343
            rootsComputationsCount      +=  1
344
            if len(iRootsList) == 0:
345
                rootsComputationsFullTime   =   cputime(rootsComputationTime)
346
                print "No roots in \"i\"."
347
                break # No roots in i.
348
            tRootsList = Zt(currentResultantT).roots()
349
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
350
            rootsComputationsCount      +=  1
351
            if len(tRootsList) == 0:
352
                print "No roots in \"t\"."
353
                break # No roots in i.
354
            ##### For each iRoot, get a tRoot and check against the polynomials.
355
            for iRoot in iRootsList:
356
                ####### Roots returned by roots() are (value, multiplicity) 
357
                #       tuples.
358
                #print "iRoot:", iRoot
359
                for tRoot in tRootsList:
360
                ###### Use the tRoot against each polynomial, alternatively.
361
                    if polyPair[0](iRoot[0],tRoot[0]) != 0:
362
                        continue
363
                    if polyPair[1](iRoot[0],tRoot[0]) != 0:
364
                        continue
365
                    rootsSet.add((iRoot[0], tRoot[0]))
366
            # End of roots computation.
367
        # End loop for polyPair in polyParsList.  Will break at next iteration.
368
        # since a non null resultant was found.
369
        #### Prepare for results for the current interval..
370
        intervalResultsList = []
371
        intervalResultsList.append((lb, ub))
372
        #### Check roots.
373
        rootsResultsList = []
374
        for root in rootsSet:
375
            specificRootResultsList = []
376
            failingBounds = []
377
            intIntPdivN = intIntP(root[0], root[1]) / N
378
            if int(intIntPdivN) != intIntPdivN:
379
                continue # Next root
380
            # Root qualifies for modular equation, test it for hardness to round.
381
            hardToRoundCaseAsFloat = RRR((icAsInt + root[0]) / toIntegerFactor)
382
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
383
            #print scalingFunction
384
            scaledHardToRoundCaseAsFloat = \
385
                scalingFunction(hardToRoundCaseAsFloat) 
386
            print "Candidate HTRNc at x =", \
387
                scaledHardToRoundCaseAsFloat.n().str(base=2),
388
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
389
                           function,
390
                           2^-(targetHardnessToRound),
391
                           RRR):
392
                print hardToRoundCaseAsFloat, "is HTRN case."
393
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
394
                    print "Found in interval."
395
                else:
396
                    print "Found out of interval."
397
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
398
                # Check the root is in the bounds
399
                if abs(root[0]) > iBound or abs(root[1]) > tBound:
400
                    print "Root", root, "is out of bounds for modular equation."
401
                    if abs(root[0]) > iBound:
402
                        print "root[0]:", root[0]
403
                        print "i bound:", iBound
404
                        failingBounds.append('i')
405
                        failingBounds.append(root[0])
406
                        failingBounds.append(iBound)
407
                    if abs(root[1]) > tBound:
408
                        print "root[1]:", root[1]
409
                        print "t bound:", tBound
410
                        failingBounds.append('t')
411
                        failingBounds.append(root[1])
412
                        failingBounds.append(tBound)
413
                if len(failingBounds) > 0:
414
                    specificRootResultsList.append(failingBounds)
415
            else: # From slz_is_htrn...
416
                print "is not an HTRN case."
417
            if len(specificRootResultsList) > 0:
418
                rootsResultsList.append(specificRootResultsList)
419
        if len(rootsResultsList) > 0:
420
            intervalResultsList.append(rootsResultsList)
421
        ### Check if a non null resultant was found. If not shrink the interval.
422
        if not hasNonNullResultant:
423
            print "Only null resultants for this reduction, shrinking interval."
424
            resultCondFailed      =  True
425
            resultCondFailedCount += 1
426
            ### Shrink interval for next iteration.
427
            ub = lb + bw * onlyNullResultantsShrink
428
            if ub > sdub:
429
                ub = sdub
430
            nbw = 0
431
            continue
432
        #### An intervalResultsList has at least the bounds.
433
        globalResultsList.append(intervalResultsList)   
434
        #### Compute an incremented width for next upper bound, only
435
        #    if not Coppersmith condition nor resultant condition
436
        #    failed at the previous run. 
437
        if not coppCondFailed and not resultCondFailed:
438
            nbw = noErrorIntervalStretch * bw
439
        else:
440
            nbw = bw
441
        ##### Reset the failure flags. They will be raised
442
        #     again if needed.
443
        coppCondFailed   = False
444
        resultCondFailed = False
445
        #### For next iteration (at end of loop)
446
        #print "nbw:", nbw
447
        lb  = ub
448
        ub += nbw     
449
        if ub > sdub:
450
            ub = sdub
451
        print
452
    # End while True
453
    ## Main loop just ended.
454
    globalWallTime = walltime(wallTimeStart)
455
    globalCpuTime  = cputime(cpuTimeStart)
456
    ## Output results
457
    print ; print "Intervals and HTRNs" ; print
458
    for intervalResultsList in globalResultsList:
459
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
460
                               "," + str(intervalResultsList[0][1])  + "]"
461
        print intervalResultString,
462
        if len(intervalResultsList) > 1:
463
            rootsResultsList = intervalResultsList[1]
464
            specificRootResultIndex = 0
465
            for specificRootResultsList in rootsResultsList:
466
                if specificRootResultIndex == 0:
467
                    print "\t", specificRootResultsList[0],
468
                else:
469
                    print " " * len(intervalResultString), "\t", \
470
                          specificRootResultsList[0],
471
                if len(specificRootResultsList) > 1:
472
                    print specificRootResultsList[1]
473
                specificRootResultIndex += 1
474
        print ; print
475
    #print globalResultsList
476
    #
477
    print "Timers and counters"
478
    print
479
    print "Number of iterations:", iterCount
480
    print "Taylor condition failures:", taylCondFailedCount
481
    print "Coppersmith condition failures:", coppCondFailedCount
482
    print "Resultant condition failures:", resultCondFailedCount
483
    print "Iterations count: ", iterCount
484
    print "Number of intervals:", len(globalResultsList)
485
    print "Number of basis constructions:", basisConstructionsCount 
486
    print "Total CPU time spent in basis constructions:", \
487
        basisConstructionsFullTime
488
    if basisConstructionsCount != 0:
489
        print "Average basis construction CPU time:", \
490
            basisConstructionsFullTime/basisConstructionsCount
491
    print "Number of reductions:", reductionsCount
492
    print "Total CPU time spent in reductions:", reductionsFullTime
493
    if reductionsCount != 0:
494
        print "Average reduction CPU time:", \
495
            reductionsFullTime/reductionsCount
496
    print "Number of resultants computation rounds:", \
497
        resultantsComputationsCount
498
    print "Total CPU time spent in resultants computation rounds:", \
499
        resultantsComputationsFullTime
500
    if resultantsComputationsCount != 0:
501
        print "Average resultants computation round CPU time:", \
502
            resultantsComputationsFullTime/resultantsComputationsCount
503
    print "Number of root finding rounds:", rootsComputationsCount
504
    print "Total CPU time spent in roots finding rounds:", \
505
        rootsComputationsFullTime
506
    if rootsComputationsCount != 0:
507
        print "Average roots finding round CPU time:", \
508
            rootsComputationsFullTime/rootsComputationsCount
509
    print "Global Wall time:", globalWallTime
510
    print "Global CPU time:", globalCpuTime
511
    ## Output counters
512
# End srs_compute_lattice_volume
513
 
514
"""
515
SLZ runtime function.
516
"""
517

    
518
def srs_run_SLZ_v01(inputFunction,
519
                    inputLowerBound,
520
                    inputUpperBound,
521
                    alpha,
522
                    degree,
523
                    precision,
524
                    emin,
525
                    emax,
526
                    targetHardnessToRound,
527
                    debug = False):
528

    
529
    if debug:
530
        print "Function                :", inputFunction
531
        print "Lower bound             :", inputLowerBound
532
        print "Upper bounds            :", inputUpperBound
533
        print "Alpha                   :", alpha
534
        print "Degree                  :", degree
535
        print "Precision               :", precision
536
        print "Emin                    :", emin
537
        print "Emax                    :", emax
538
        print "Target hardness-to-round:", targetHardnessToRound
539
        print
540
    ## Important constants.
541
    ### Stretch the interval if no error happens.
542
    noErrorIntervalStretch = 1 + 2^(-5)
543
    ### If no vector validates the Coppersmith condition, shrink the interval
544
    #   by the following factor.
545
    noCoppersmithIntervalShrink = 1/2
546
    ### If only (or at least) one vector validates the Coppersmith condition, 
547
    #   shrink the interval by the following factor.
548
    oneCoppersmithIntervalShrink = 3/4
549
    #### If only null resultants are found, shrink the interval by the 
550
    #    following factor.
551
    onlyNullResultantsShrink     = 3/4
552
    ## Structures.
553
    RRR         = RealField(precision)
554
    RRIF        = RealIntervalField(precision)
555
    ## Converting input bound into the "right" field.
556
    lowerBound = RRR(inputLowerBound)
557
    upperBound = RRR(inputUpperBound)
558
    ## Before going any further, check domain and image binade conditions.
559
    print inputFunction(1).n()
560
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
561
    if output is None:
562
        print "Invalid domain/image binades. Domain:",\
563
        lowerBound, upperBound, "Images:", \
564
        inputFunction(lowerBound), inputFunction(upperBound)
565
        raise Exception("Invalid domain/image binades.")
566
    lb = output[0] ; ub = output[1]
567
    if lb is None or lb != lowerBound or ub != upperBound:
568
        print "lb:", lb, " - ub:", ub
569
        print "Invalid domain/image binades. Domain:",\
570
        lowerBound, upperBound, "Images:", \
571
        inputFunction(lowerBound), inputFunction(upperBound)
572
        raise Exception("Invalid domain/image binades.")
573
    #
574
    ## Progam initialization
575
    ### Approximation polynomial accuracy and hardness to round.
576
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
577
    polyTargetHardnessToRound = targetHardnessToRound + 1
578
    ### Significand to integer conversion ratio.
579
    toIntegerFactor           = 2^(precision-1)
580
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
581
    ### Variables and rings for polynomials and root searching.
582
    i=var('i')
583
    t=var('t')
584
    inputFunctionVariable = inputFunction.variables()[0]
585
    function = inputFunction.subs({inputFunctionVariable:i})
586
    #  Polynomial Rings over the integers, for root finding.
587
    Zi = ZZ[i]
588
    Zt = ZZ[t]
589
    Zit = ZZ[i,t]
590
    ## Number of iterations limit.
591
    maxIter = 100000
592
    #
593
    ## Compute the scaled function and the degree, in their Sollya version 
594
    #  once for all.
595
    (scaledf, sdlb, sdub, silb, siub) = \
596
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
597
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
598
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
599
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
600
    #
601
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
602
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
603
    (unscalingFunction, scalingFunction) = \
604
        slz_interval_scaling_expression(domainBoundsInterval, i)
605
    #print scalingFunction, unscalingFunction
606
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
607
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
608
    if internalSollyaPrec < 192:
609
        internalSollyaPrec = 192
610
    pobyso_set_prec_sa_so(internalSollyaPrec)
611
    print "Sollya internal precision:", internalSollyaPrec
612
    ## Some variables.
613
    ### General variables
614
    lb                  = sdlb
615
    ub                  = sdub
616
    nbw                 = 0
617
    intervalUlp         = ub.ulp()
618
    #### Will be set by slz_interval_and_polynomila_to_sage.
619
    ic                  = 0 
620
    icAsInt             = 0    # Set from ic.
621
    solutionsSet        = set()
622
    tsErrorWidth        = []
623
    csErrorVectors      = []
624
    csVectorsResultants = []
625
    floatP              = 0  # Taylor polynomial.
626
    floatPcv            = 0  # Ditto with variable change.
627
    intvl               = "" # Taylor interval
628
    terr                = 0  # Taylor error.
629
    iterCount = 0
630
    htrnSet = set()
631
    ### Timers and counters.
632
    wallTimeStart                   = 0
633
    cpuTimeStart                    = 0
634
    taylCondFailedCount             = 0
635
    coppCondFailedCount             = 0
636
    resultCondFailedCount           = 0
637
    coppCondFailed                  = False
638
    resultCondFailed                = False
639
    globalResultsList               = []
640
    basisConstructionsCount         = 0
641
    basisConstructionsFullTime      = 0
642
    basisConstructionTime           = 0
643
    reductionsCount                 = 0
644
    reductionsFullTime              = 0
645
    reductionTime                   = 0
646
    resultantsComputationsCount     = 0
647
    resultantsComputationsFullTime  = 0
648
    resultantsComputationTime       = 0
649
    rootsComputationsCount          = 0
650
    rootsComputationsFullTime       = 0
651
    rootsComputationTime            = 0
652
    print
653
    ## Global times are started here.
654
    wallTimeStart                   = walltime()
655
    cpuTimeStart                    = cputime()
656
    ## Main loop.
657
    while True:
658
        if lb >= sdub:
659
            print "Lower bound reached upper bound."
660
            break
661
        if iterCount == maxIter:
662
            print "Reached maxIter. Aborting"
663
            break
664
        iterCount += 1
665
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
666
            "log2(numbers)." 
667
        ### Compute a Sollya polynomial that will honor the Taylor condition.
668
        prceSo = slz_compute_polynomial_and_interval(scaledfSo,
669
                                                     degreeSo,
670
                                                     lb,
671
                                                     ub,
672
                                                     polyApproxAccur)
673
        ### Convert back the data into Sage space.                         
674
        (floatP, floatPcv, intvl, ic, terr) = \
675
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
676
                                                 prceSo[1], prceSo[2], 
677
                                                 prceSo[3]))
678
        intvl = RRIF(intvl)
679
        ## Clean-up Sollya stuff.
680
        for elem in prceSo:
681
            sollya_lib_clear_obj(elem)
682
        #print  floatP, floatPcv, intvl, ic, terr
683
        #print floatP
684
        #print intvl.endpoints()[0].n(), \
685
        #      ic.n(),
686
        #intvl.endpoints()[1].n()
687
        ### Check returned data.
688
        #### Is approximation error OK?
689
        if terr > polyApproxAccur:
690
            exceptionErrorMess  = \
691
                "Approximation failed - computed error:" + \
692
                str(terr) + " - target error: "
693
            exceptionErrorMess += \
694
                str(polyApproxAccur) + ". Aborting!"
695
            raise Exception(exceptionErrorMess)
696
        #### Is lower bound OK?
697
        if lb != intvl.endpoints()[0]:
698
            exceptionErrorMess =  "Wrong lower bound:" + \
699
                               str(lb) + ". Aborting!"
700
            raise Exception(exceptionErrorMess)
701
        #### Set upper bound.
702
        if ub > intvl.endpoints()[1]:
703
            ub = intvl.endpoints()[1]
704
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
705
            "log2(numbers)." 
706
            taylCondFailedCount += 1
707
        #### Is interval not degenerate?
708
        if lb >= ub:
709
            exceptionErrorMess = "Degenerate interval: " + \
710
                                "lowerBound(" + str(lb) +\
711
                                ")>= upperBound(" + str(ub) + \
712
                                "). Aborting!"
713
            raise Exception(exceptionErrorMess)
714
        #### Is interval center ok?
715
        if ic <= lb or ic >= ub:
716
            exceptionErrorMess =  "Invalid interval center for " + \
717
                                str(lb) + ',' + str(ic) + ',' +  \
718
                                str(ub) + ". Aborting!"
719
            raise Exception(exceptionErrorMess)
720
        ##### Current interval width and reset future interval width.
721
        bw = ub - lb
722
        nbw = 0
723
        icAsInt = int(ic * toIntegerFactor)
724
        #### The following ratio is always >= 1. In case we may want to
725
        #  enlarge the interval
726
        curTaylErrRat = polyApproxAccur / terr
727
        ## Make the  integral transformations.
728
        ### First for interval center and bounds.
729
        intIc = int(ic * toIntegerFactor)
730
        intLb = int(lb * toIntegerFactor) - intIc
731
        intUb = int(ub * toIntegerFactor) - intIc
732
        #
733
        #### For polynomials
734
        basisConstructionTime         = cputime()
735
        ##### To a polynomial with rational coefficients with rational arguments
736
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
737
        ##### To a polynomial with rational coefficients with integer arguments
738
        ratIntP = \
739
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
740
        #####  Ultimately a polynomial with integer coefficients with integer 
741
        #      arguments.
742
        coppersmithTuple = \
743
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
744
                                                        precision, 
745
                                                        targetHardnessToRound, 
746
                                                        i, t)
747
        #### Recover Coppersmith information.
748
        intIntP = coppersmithTuple[0]
749
        N = coppersmithTuple[1]
750
        nAtAlpha = N^alpha
751
        tBound = coppersmithTuple[2]
752
        leastCommonMultiple = coppersmithTuple[3]
753
        iBound = max(abs(intLb),abs(intUb))
754
        basisConstructionsFullTime        += cputime(basisConstructionTime)
755
        basisConstructionsCount           += 1
756
        reductionTime                     = cputime()
757
        # Compute the reduced polynomials.
758
        ccReducedPolynomialsList =  \
759
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
760
                                                            alpha, 
761
                                                            N, 
762
                                                            iBound, 
763
                                                            tBound)
764
        if ccReducedPolynomialsList is None:
765
            raise Exception("Reduction failed.")
766
        reductionsFullTime    += cputime(reductionTime)
767
        reductionsCount       += 1
768
        if len(ccReducedPolynomialsList) < 2:
769
            print "Nothing to form resultants with."
770
            print
771
            coppCondFailedCount += 1
772
            coppCondFailed = True
773
            ##### Apply a different shrink factor according to 
774
            #  the number of compliant polynomials.
775
            if len(ccReducedPolynomialsList) == 0:
776
                ub = lb + bw * noCoppersmithIntervalShrink
777
            else: # At least one compliant polynomial.
778
                ub = lb + bw * oneCoppersmithIntervalShrink
779
            if ub > sdub:
780
                ub = sdub
781
            if lb == ub:
782
                raise Exception("Cant shrink interval \
783
                anymore to get Coppersmith condition.")
784
            nbw = 0
785
            continue
786
        #### We have at least two polynomials.
787
        #    Let us try to compute resultants.
788
        resultantsComputationTime      = cputime()
789
        resultantsInTTuplesList = []
790
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
791
            for polyInnerIndex in xrange(polyOuterIndex+1, 
792
                                         len(ccReducedPolynomialsList)):
793
                resultantTuple = \
794
                slz_resultant_tuple(ccReducedPolynomialsList[polyOuterIndex],
795
                                ccReducedPolynomialsList[polyInnerIndex],
796
                                t)
797
                if len(resultantTuple) > 2:                    
798
                    #print resultantTuple[2]
799
                    resultantsInTTuplesList.append(resultantTuple)
800
                else:
801
                    print "No non nul resultant"
802
        print len(resultantsInTTuplesList), "resultant(s) in t tuple(s) created."
803
        resultantsComputationsFullTime += cputime(resultantsComputationTime)
804
        resultantsComputationsCount    += 1
805
        if len(resultantsInTTuplesList) == 0:
806
            print "Only null resultants, shrinking interval."
807
            resultCondFailed      =  True
808
            resultCondFailedCount += 1
809
            ### Shrink interval for next iteration.
810
            ub = lb + bw * onlyNullResultantsShrink
811
            if ub > sdub:
812
                ub = sdub
813
            nbw = 0
814
            continue
815
        #### Compute roots.
816
        rootsComputationTime       = cputime()
817
        reducedPolynomialsRootsSet = set()
818
        ##### Solve in the second variable since resultants are in the first
819
        #     variable.
820
        for resultantInTTuple in resultantsInTTuplesList:
821
            currentResultant = resultantInTTuple[2]
822
            ##### If the resultant degree is not at least 1, there are no roots.
823
            if currentResultant.degree() < 1:
824
                print "Resultant is constant:", currentResultant
825
                continue # Next resultantInTTuple
826
            ##### Compute i roots
827
            iRootsList = Zi(currentResultant).roots()
828
            ##### For each iRoot, compute the corresponding tRoots and check 
829
            #     them in the input polynomial.
830
            for iRoot in iRootsList:
831
                ####### Roots returned by roots() are (value, multiplicity) 
832
                #       tuples.
833
                #print "iRoot:", iRoot
834
                ###### Use the tRoot against each polynomial, alternatively.
835
                for indexInTuple in range(0,2):
836
                    currentPolynomial = resultantInTTuple[indexInTuple]
837
                    ####### If the polynomial is univariate, just drop it.
838
                    if len(currentPolynomial.variables()) < 2:
839
                        print "    Current polynomial is not in two variables."
840
                        continue # Next indexInTuple
841
                    tRootsList = \
842
                        Zt(currentPolynomial.subs({currentPolynomial.variables()[0]:iRoot[0]})).roots()
843
                    ####### The tRootsList can be empty, hence the test.
844
                    if len(tRootsList) == 0:
845
                        print "    No t root."
846
                        continue # Next indexInTuple
847
                    for tRoot in tRootsList:
848
                        reducedPolynomialsRootsSet.add((iRoot[0], tRoot[0]))
849
        # End of roots computation
850
        rootsComputationsFullTime   =   cputime(rootsComputationTime)
851
        rootsComputationsCount      +=  1
852
        ##### Prepare for results.
853
        intervalResultsList = []
854
        intervalResultsList.append((lb, ub))
855
        #### Check roots.
856
        rootsResultsList = []
857
        for root in reducedPolynomialsRootsSet:
858
            specificRootResultsList = []
859
            failingBounds = []
860
            intIntPdivN = intIntP(root[0], root[1]) / N
861
            if int(intIntPdivN) != intIntPdivN:
862
                continue # Next root
863
            # Root qualifies for modular equation, test it for hardness to round.
864
            hardToRoundCaseAsFloat = RRR((icAsInt + root[0]) / toIntegerFactor)
865
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
866
            #print scalingFunction
867
            scaledHardToRoundCaseAsFloat = \
868
                scalingFunction(hardToRoundCaseAsFloat) 
869
            print "Candidate HTRNc at x =", \
870
                scaledHardToRoundCaseAsFloat.n().str(base=2),
871
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
872
                           function,
873
                           2^-(targetHardnessToRound),
874
                           RRR):
875
                print hardToRoundCaseAsFloat, "is HTRN case."
876
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
877
                    print "Found in interval."
878
                else:
879
                    print "Found out of interval."
880
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
881
                # Check the root is in the bounds
882
                if abs(root[0]) > iBound or abs(root[1]) > tBound:
883
                    print "Root", root, "is out of bounds."
884
                    if abs(root[0]) > iBound:
885
                        print "root[0]:", root[0]
886
                        print "i bound:", iBound
887
                        failingBounds.append('i')
888
                        failingBounds.append(root[0])
889
                        failingBounds.append(iBound)
890
                    if abs(root[1]) > tBound:
891
                        print "root[1]:", root[1]
892
                        print "t bound:", tBound
893
                        failingBounds.append('t')
894
                        failingBounds.append(root[1])
895
                        failingBounds.append(tBound)
896
                if len(failingBounds) > 0:
897
                    specificRootResultsList.append(failingBounds)
898
            else: # From slz_is_htrn...
899
                print "is not an HTRN case."
900
            if len(specificRootResultsList) > 0:
901
                rootsResultsList.append(specificRootResultsList)
902
        if len(rootsResultsList) > 0:
903
            intervalResultsList.append(rootsResultsList)
904
        #### An intervalResultsList has at least the bounds.
905
        globalResultsList.append(intervalResultsList)   
906
        #### Compute an incremented width for next upper bound, only
907
        #    if not Coppersmith condition nor resultant condition
908
        #    failed at the previous run. 
909
        if not coppCondFailed and not resultCondFailed:
910
            nbw = noErrorIntervalStretch * bw
911
        else:
912
            nbw = bw
913
        ##### Reset the failure flags. They will be raised
914
        #     again if needed.
915
        coppCondFailed   = False
916
        resultCondFailed = False
917
        #### For next iteration (at end of loop)
918
        #print "nbw:", nbw
919
        lb  = ub
920
        ub += nbw     
921
        if ub > sdub:
922
            ub = sdub
923
        print
924
    # End while True
925
    ## Main loop just ended.
926
    globalWallTime = walltime(wallTimeStart)
927
    globalCpuTime  = cputime(cpuTimeStart)
928
    ## Output results
929
    print ; print "Intervals and HTRNs" ; print
930
    for intervalResultsList in globalResultsList:
931
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
932
                               "," + str(intervalResultsList[0][1])  + "]"
933
        print intervalResultString,
934
        if len(intervalResultsList) > 1:
935
            rootsResultsList = intervalResultsList[1]
936
            specificRootResultIndex = 0
937
            for specificRootResultsList in rootsResultsList:
938
                if specificRootResultIndex == 0:
939
                    print "\t", specificRootResultsList[0],
940
                else:
941
                    print " " * len(intervalResultString), "\t", \
942
                          specificRootResultsList[0],
943
                if len(specificRootResultsList) > 1:
944
                    print specificRootResultsList[1]
945
                specificRootResultIndex += 1
946
        print ; print
947
    #print globalResultsList
948
    #
949
    print "Timers and counters"
950
    print
951
    print "Number of iterations:", iterCount
952
    print "Taylor condition failures:", taylCondFailedCount
953
    print "Coppersmith condition failures:", coppCondFailedCount
954
    print "Resultant condition failures:", resultCondFailedCount
955
    print "Iterations count: ", iterCount
956
    print "Number of intervals:", len(globalResultsList)
957
    print "Number of basis constructions:", basisConstructionsCount 
958
    print "Total CPU time spent in basis constructions:", \
959
        basisConstructionsFullTime
960
    if basisConstructionsCount != 0:
961
        print "Average basis construction CPU time:", \
962
            basisConstructionsFullTime/basisConstructionsCount
963
    print "Number of reductions:", reductionsCount
964
    print "Total CPU time spent in reductions:", reductionsFullTime
965
    if reductionsCount != 0:
966
        print "Average reduction CPU time:", \
967
            reductionsFullTime/reductionsCount
968
    print "Number of resultants computation rounds:", \
969
        resultantsComputationsCount
970
    print "Total CPU time spent in resultants computation rounds:", \
971
        resultantsComputationsFullTime
972
    if resultantsComputationsCount != 0:
973
        print "Average resultants computation round CPU time:", \
974
            resultantsComputationsFullTime/resultantsComputationsCount
975
    print "Number of root finding rounds:", rootsComputationsCount
976
    print "Total CPU time spent in roots finding rounds:", \
977
        rootsComputationsFullTime
978
    if rootsComputationsCount != 0:
979
        print "Average roots finding round CPU time:", \
980
            rootsComputationsFullTime/rootsComputationsCount
981
    print "Global Wall time:", globalWallTime
982
    print "Global CPU time:", globalCpuTime
983
    ## Output counters
984
# End srs_runSLZ-v01
985

    
986
def srs_run_SLZ_v02(inputFunction,
987
                    inputLowerBound,
988
                    inputUpperBound,
989
                    alpha,
990
                    degree,
991
                    precision,
992
                    emin,
993
                    emax,
994
                    targetHardnessToRound,
995
                    debug = False):
996
    """
997
    Changes from V1: 
998
        1- check for roots as soon as a resultant is computed;
999
        2- once a non null resultant is found, check for roots;
1000
        3- constant resultant == no root.
1001
    """
1002

    
1003
    if debug:
1004
        print "Function                :", inputFunction
1005
        print "Lower bound             :", inputLowerBound
1006
        print "Upper bounds            :", inputUpperBound
1007
        print "Alpha                   :", alpha
1008
        print "Degree                  :", degree
1009
        print "Precision               :", precision
1010
        print "Emin                    :", emin
1011
        print "Emax                    :", emax
1012
        print "Target hardness-to-round:", targetHardnessToRound
1013
        print
1014
    ## Important constants.
1015
    ### Stretch the interval if no error happens.
1016
    noErrorIntervalStretch = 1 + 2^(-5)
1017
    ### If no vector validates the Coppersmith condition, shrink the interval
1018
    #   by the following factor.
1019
    noCoppersmithIntervalShrink = 1/2
1020
    ### If only (or at least) one vector validates the Coppersmith condition, 
1021
    #   shrink the interval by the following factor.
1022
    oneCoppersmithIntervalShrink = 3/4
1023
    #### If only null resultants are found, shrink the interval by the 
1024
    #    following factor.
1025
    onlyNullResultantsShrink     = 3/4
1026
    ## Structures.
1027
    RRR         = RealField(precision)
1028
    RRIF        = RealIntervalField(precision)
1029
    ## Converting input bound into the "right" field.
1030
    lowerBound = RRR(inputLowerBound)
1031
    upperBound = RRR(inputUpperBound)
1032
    ## Before going any further, check domain and image binade conditions.
1033
    print inputFunction(1).n()
1034
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
1035
    if output is None:
1036
        print "Invalid domain/image binades. Domain:",\
1037
        lowerBound, upperBound, "Images:", \
1038
        inputFunction(lowerBound), inputFunction(upperBound)
1039
        raise Exception("Invalid domain/image binades.")
1040
    lb = output[0] ; ub = output[1]
1041
    if lb != lowerBound or ub != upperBound:
1042
        print "lb:", lb, " - ub:", ub
1043
        print "Invalid domain/image binades. Domain:",\
1044
        lowerBound, upperBound, "Images:", \
1045
        inputFunction(lowerBound), inputFunction(upperBound)
1046
        raise Exception("Invalid domain/image binades.")
1047
    #
1048
    ## Progam initialization
1049
    ### Approximation polynomial accuracy and hardness to round.
1050
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
1051
    polyTargetHardnessToRound = targetHardnessToRound + 1
1052
    ### Significand to integer conversion ratio.
1053
    toIntegerFactor           = 2^(precision-1)
1054
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
1055
    ### Variables and rings for polynomials and root searching.
1056
    i=var('i')
1057
    t=var('t')
1058
    inputFunctionVariable = inputFunction.variables()[0]
1059
    function = inputFunction.subs({inputFunctionVariable:i})
1060
    #  Polynomial Rings over the integers, for root finding.
1061
    Zi = ZZ[i]
1062
    Zt = ZZ[t]
1063
    Zit = ZZ[i,t]
1064
    ## Number of iterations limit.
1065
    maxIter = 100000
1066
    #
1067
    ## Compute the scaled function and the degree, in their Sollya version 
1068
    #  once for all.
1069
    (scaledf, sdlb, sdub, silb, siub) = \
1070
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
1071
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
1072
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
1073
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
1074
    #
1075
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
1076
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
1077
    (unscalingFunction, scalingFunction) = \
1078
        slz_interval_scaling_expression(domainBoundsInterval, i)
1079
    #print scalingFunction, unscalingFunction
1080
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
1081
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
1082
    if internalSollyaPrec < 192:
1083
        internalSollyaPrec = 192
1084
    pobyso_set_prec_sa_so(internalSollyaPrec)
1085
    print "Sollya internal precision:", internalSollyaPrec
1086
    ## Some variables.
1087
    ### General variables
1088
    lb                  = sdlb
1089
    ub                  = sdub
1090
    nbw                 = 0
1091
    intervalUlp         = ub.ulp()
1092
    #### Will be set by slz_interval_and_polynomila_to_sage.
1093
    ic                  = 0 
1094
    icAsInt             = 0    # Set from ic.
1095
    solutionsSet        = set()
1096
    tsErrorWidth        = []
1097
    csErrorVectors      = []
1098
    csVectorsResultants = []
1099
    floatP              = 0  # Taylor polynomial.
1100
    floatPcv            = 0  # Ditto with variable change.
1101
    intvl               = "" # Taylor interval
1102
    terr                = 0  # Taylor error.
1103
    iterCount = 0
1104
    htrnSet = set()
1105
    ### Timers and counters.
1106
    wallTimeStart                   = 0
1107
    cpuTimeStart                    = 0
1108
    taylCondFailedCount             = 0
1109
    coppCondFailedCount             = 0
1110
    resultCondFailedCount           = 0
1111
    coppCondFailed                  = False
1112
    resultCondFailed                = False
1113
    globalResultsList               = []
1114
    basisConstructionsCount         = 0
1115
    basisConstructionsFullTime      = 0
1116
    basisConstructionTime           = 0
1117
    reductionsCount                 = 0
1118
    reductionsFullTime              = 0
1119
    reductionTime                   = 0
1120
    resultantsComputationsCount     = 0
1121
    resultantsComputationsFullTime  = 0
1122
    resultantsComputationTime       = 0
1123
    rootsComputationsCount          = 0
1124
    rootsComputationsFullTime       = 0
1125
    rootsComputationTime            = 0
1126
    print
1127
    ## Global times are started here.
1128
    wallTimeStart                   = walltime()
1129
    cpuTimeStart                    = cputime()
1130
    ## Main loop.
1131
    while True:
1132
        if lb >= sdub:
1133
            print "Lower bound reached upper bound."
1134
            break
1135
        if iterCount == maxIter:
1136
            print "Reached maxIter. Aborting"
1137
            break
1138
        iterCount += 1
1139
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
1140
            "log2(numbers)." 
1141
        ### Compute a Sollya polynomial that will honor the Taylor condition.
1142
        prceSo = slz_compute_polynomial_and_interval(scaledfSo,
1143
                                                     degreeSo,
1144
                                                     lb,
1145
                                                     ub,
1146
                                                     polyApproxAccur)
1147
        ### Convert back the data into Sage space.                         
1148
        (floatP, floatPcv, intvl, ic, terr) = \
1149
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
1150
                                                 prceSo[1], prceSo[2], 
1151
                                                 prceSo[3]))
1152
        intvl = RRIF(intvl)
1153
        ## Clean-up Sollya stuff.
1154
        for elem in prceSo:
1155
            sollya_lib_clear_obj(elem)
1156
        #print  floatP, floatPcv, intvl, ic, terr
1157
        #print floatP
1158
        #print intvl.endpoints()[0].n(), \
1159
        #      ic.n(),
1160
        #intvl.endpoints()[1].n()
1161
        ### Check returned data.
1162
        #### Is approximation error OK?
1163
        if terr > polyApproxAccur:
1164
            exceptionErrorMess  = \
1165
                "Approximation failed - computed error:" + \
1166
                str(terr) + " - target error: "
1167
            exceptionErrorMess += \
1168
                str(polyApproxAccur) + ". Aborting!"
1169
            raise Exception(exceptionErrorMess)
1170
        #### Is lower bound OK?
1171
        if lb != intvl.endpoints()[0]:
1172
            exceptionErrorMess =  "Wrong lower bound:" + \
1173
                               str(lb) + ". Aborting!"
1174
            raise Exception(exceptionErrorMess)
1175
        #### Set upper bound.
1176
        if ub > intvl.endpoints()[1]:
1177
            ub = intvl.endpoints()[1]
1178
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
1179
            "log2(numbers)." 
1180
            taylCondFailedCount += 1
1181
        #### Is interval not degenerate?
1182
        if lb >= ub:
1183
            exceptionErrorMess = "Degenerate interval: " + \
1184
                                "lowerBound(" + str(lb) +\
1185
                                ")>= upperBound(" + str(ub) + \
1186
                                "). Aborting!"
1187
            raise Exception(exceptionErrorMess)
1188
        #### Is interval center ok?
1189
        if ic <= lb or ic >= ub:
1190
            exceptionErrorMess =  "Invalid interval center for " + \
1191
                                str(lb) + ',' + str(ic) + ',' +  \
1192
                                str(ub) + ". Aborting!"
1193
            raise Exception(exceptionErrorMess)
1194
        ##### Current interval width and reset future interval width.
1195
        bw = ub - lb
1196
        nbw = 0
1197
        icAsInt = int(ic * toIntegerFactor)
1198
        #### The following ratio is always >= 1. In case we may want to
1199
        #    enlarge the interval
1200
        curTaylErrRat = polyApproxAccur / terr
1201
        ### Make the  integral transformations.
1202
        #### Bounds and interval center.
1203
        intIc = int(ic * toIntegerFactor)
1204
        intLb = int(lb * toIntegerFactor) - intIc
1205
        intUb = int(ub * toIntegerFactor) - intIc
1206
        #
1207
        #### Polynomials
1208
        basisConstructionTime         = cputime()
1209
        ##### To a polynomial with rational coefficients with rational arguments
1210
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
1211
        ##### To a polynomial with rational coefficients with integer arguments
1212
        ratIntP = \
1213
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
1214
        #####  Ultimately a multivariate polynomial with integer coefficients  
1215
        #      with integer arguments.
1216
        coppersmithTuple = \
1217
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
1218
                                                        precision, 
1219
                                                        targetHardnessToRound, 
1220
                                                        i, t)
1221
        #### Recover Coppersmith information.
1222
        intIntP = coppersmithTuple[0]
1223
        N = coppersmithTuple[1]
1224
        nAtAlpha = N^alpha
1225
        tBound = coppersmithTuple[2]
1226
        leastCommonMultiple = coppersmithTuple[3]
1227
        iBound = max(abs(intLb),abs(intUb))
1228
        basisConstructionsFullTime        += cputime(basisConstructionTime)
1229
        basisConstructionsCount           += 1
1230
        reductionTime                     = cputime()
1231
        #### Compute the reduced polynomials.
1232
        ccReducedPolynomialsList =  \
1233
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
1234
                                                            alpha, 
1235
                                                            N, 
1236
                                                            iBound, 
1237
                                                            tBound)
1238
        if ccReducedPolynomialsList is None:
1239
            raise Exception("Reduction failed.")
1240
        reductionsFullTime    += cputime(reductionTime)
1241
        reductionsCount       += 1
1242
        if len(ccReducedPolynomialsList) < 2:
1243
            print "Nothing to form resultants with."
1244
            print
1245
            coppCondFailedCount += 1
1246
            coppCondFailed = True
1247
            ##### Apply a different shrink factor according to 
1248
            #  the number of compliant polynomials.
1249
            if len(ccReducedPolynomialsList) == 0:
1250
                ub = lb + bw * noCoppersmithIntervalShrink
1251
            else: # At least one compliant polynomial.
1252
                ub = lb + bw * oneCoppersmithIntervalShrink
1253
            if ub > sdub:
1254
                ub = sdub
1255
            if lb == ub:
1256
                raise Exception("Cant shrink interval \
1257
                anymore to get Coppersmith condition.")
1258
            nbw = 0
1259
            continue
1260
        #### We have at least two polynomials.
1261
        #    Let us try to compute resultants.
1262
        #    For each resultant computed, go for the solutions.
1263
        ##### Build the pairs list.
1264
        polyPairsList           = []
1265
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
1266
            for polyInnerIndex in xrange(polyOuterIndex+1, 
1267
                                         len(ccReducedPolynomialsList)):
1268
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
1269
                                      ccReducedPolynomialsList[polyInnerIndex]))
1270
        #### Actual root search.
1271
        rootsSet            = set()
1272
        hasNonNullResultant = False
1273
        for polyPair in polyPairsList:
1274
            if hasNonNullResultant:
1275
                break
1276
            resultantsComputationTime   = cputime()
1277
            currentResultant = \
1278
                slz_resultant(polyPair[0],
1279
                              polyPair[1],
1280
                              t)
1281
            resultantsComputationsFullTime += cputime(resultantsComputationTime)
1282
            resultantsComputationsCount    += 1
1283
            if currentResultant is None:                    
1284
                print "Nul resultant"
1285
                continue # Next polyPair.
1286
            else:
1287
                hasNonNullResultant = True
1288
            #### We have a non null resultant. From now on, whatever the
1289
            #    root search yields, no extra root search is necessary.
1290
            #### A constant resultant leads to no root. Root search is done.
1291
            if currentResultant.degree() < 1:
1292
                print "Resultant is constant:", currentResultant
1293
                continue # Next polyPair and should break.
1294
            #### Actual roots computation.
1295
            rootsComputationTime       = cputime()
1296
            ##### Compute i roots
1297
            iRootsList = Zi(currentResultant).roots()
1298
            ##### For each iRoot, compute the corresponding tRoots and 
1299
            #     and build populate the .rootsSet.
1300
            for iRoot in iRootsList:
1301
                ####### Roots returned by roots() are (value, multiplicity) 
1302
                #       tuples.
1303
                #print "iRoot:", iRoot
1304
                ###### Use the tRoot against each polynomial, alternatively.
1305
                for indexInPair in range(0,2):
1306
                    currentPolynomial = polyPair[indexInPair]
1307
                    ####### If the polynomial is univariate, just drop it.
1308
                    if len(currentPolynomial.variables()) < 2:
1309
                        print "    Current polynomial is not in two variables."
1310
                        continue # Next indexInPair
1311
                    tRootsList = \
1312
                        Zt(currentPolynomial.subs({currentPolynomial.variables()[0]:iRoot[0]})).roots()
1313
                    ####### The tRootsList can be empty, hence the test.
1314
                    if len(tRootsList) == 0:
1315
                        print "    No t root."
1316
                        continue # Next indexInPair
1317
                    for tRoot in tRootsList:
1318
                        rootsSet.add((iRoot[0], tRoot[0]))
1319
            # End of roots computation.
1320
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
1321
            rootsComputationsCount      +=  1
1322
        # End loop for polyPair in polyParsList.  Will break at next iteration.
1323
        # since a non null resultant was found.
1324
        #### Prepare for results for the current interval..
1325
        intervalResultsList = []
1326
        intervalResultsList.append((lb, ub))
1327
        #### Check roots.
1328
        rootsResultsList = []
1329
        for root in rootsSet:
1330
            specificRootResultsList = []
1331
            failingBounds = []
1332
            intIntPdivN = intIntP(root[0], root[1]) / N
1333
            if int(intIntPdivN) != intIntPdivN:
1334
                continue # Next root
1335
            # Root qualifies for modular equation, test it for hardness to round.
1336
            hardToRoundCaseAsFloat = RRR((icAsInt + root[0]) / toIntegerFactor)
1337
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
1338
            #print scalingFunction
1339
            scaledHardToRoundCaseAsFloat = \
1340
                scalingFunction(hardToRoundCaseAsFloat) 
1341
            print "Candidate HTRNc at x =", \
1342
                scaledHardToRoundCaseAsFloat.n().str(base=2),
1343
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
1344
                           function,
1345
                           2^-(targetHardnessToRound),
1346
                           RRR):
1347
                print hardToRoundCaseAsFloat, "is HTRN case."
1348
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
1349
                    print "Found in interval."
1350
                else:
1351
                    print "Found out of interval."
1352
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
1353
                # Check the root is in the bounds
1354
                if abs(root[0]) > iBound or abs(root[1]) > tBound:
1355
                    print "Root", root, "is out of bounds for modular equation."
1356
                    if abs(root[0]) > iBound:
1357
                        print "root[0]:", root[0]
1358
                        print "i bound:", iBound
1359
                        failingBounds.append('i')
1360
                        failingBounds.append(root[0])
1361
                        failingBounds.append(iBound)
1362
                    if abs(root[1]) > tBound:
1363
                        print "root[1]:", root[1]
1364
                        print "t bound:", tBound
1365
                        failingBounds.append('t')
1366
                        failingBounds.append(root[1])
1367
                        failingBounds.append(tBound)
1368
                if len(failingBounds) > 0:
1369
                    specificRootResultsList.append(failingBounds)
1370
            else: # From slz_is_htrn...
1371
                print "is not an HTRN case."
1372
            if len(specificRootResultsList) > 0:
1373
                rootsResultsList.append(specificRootResultsList)
1374
        if len(rootsResultsList) > 0:
1375
            intervalResultsList.append(rootsResultsList)
1376
        ### Check if a non null resultant was found. If not shrink the interval.
1377
        if not hasNonNullResultant:
1378
            print "Only null resultants for this reduction, shrinking interval."
1379
            resultCondFailed      =  True
1380
            resultCondFailedCount += 1
1381
            ### Shrink interval for next iteration.
1382
            ub = lb + bw * onlyNullResultantsShrink
1383
            if ub > sdub:
1384
                ub = sdub
1385
            nbw = 0
1386
            continue
1387
        #### An intervalResultsList has at least the bounds.
1388
        globalResultsList.append(intervalResultsList)   
1389
        #### Compute an incremented width for next upper bound, only
1390
        #    if not Coppersmith condition nor resultant condition
1391
        #    failed at the previous run. 
1392
        if not coppCondFailed and not resultCondFailed:
1393
            nbw = noErrorIntervalStretch * bw
1394
        else:
1395
            nbw = bw
1396
        ##### Reset the failure flags. They will be raised
1397
        #     again if needed.
1398
        coppCondFailed   = False
1399
        resultCondFailed = False
1400
        #### For next iteration (at end of loop)
1401
        #print "nbw:", nbw
1402
        lb  = ub
1403
        ub += nbw     
1404
        if ub > sdub:
1405
            ub = sdub
1406
        print
1407
    # End while True
1408
    ## Main loop just ended.
1409
    globalWallTime = walltime(wallTimeStart)
1410
    globalCpuTime  = cputime(cpuTimeStart)
1411
    ## Output results
1412
    print ; print "Intervals and HTRNs" ; print
1413
    for intervalResultsList in globalResultsList:
1414
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
1415
                               "," + str(intervalResultsList[0][1])  + "]"
1416
        print intervalResultString,
1417
        if len(intervalResultsList) > 1:
1418
            rootsResultsList = intervalResultsList[1]
1419
            specificRootResultIndex = 0
1420
            for specificRootResultsList in rootsResultsList:
1421
                if specificRootResultIndex == 0:
1422
                    print "\t", specificRootResultsList[0],
1423
                else:
1424
                    print " " * len(intervalResultString), "\t", \
1425
                          specificRootResultsList[0],
1426
                if len(specificRootResultsList) > 1:
1427
                    print specificRootResultsList[1]
1428
                specificRootResultIndex += 1
1429
        print ; print
1430
    #print globalResultsList
1431
    #
1432
    print "Timers and counters"
1433
    print
1434
    print "Number of iterations:", iterCount
1435
    print "Taylor condition failures:", taylCondFailedCount
1436
    print "Coppersmith condition failures:", coppCondFailedCount
1437
    print "Resultant condition failures:", resultCondFailedCount
1438
    print "Iterations count: ", iterCount
1439
    print "Number of intervals:", len(globalResultsList)
1440
    print "Number of basis constructions:", basisConstructionsCount 
1441
    print "Total CPU time spent in basis constructions:", \
1442
        basisConstructionsFullTime
1443
    if basisConstructionsCount != 0:
1444
        print "Average basis construction CPU time:", \
1445
            basisConstructionsFullTime/basisConstructionsCount
1446
    print "Number of reductions:", reductionsCount
1447
    print "Total CPU time spent in reductions:", reductionsFullTime
1448
    if reductionsCount != 0:
1449
        print "Average reduction CPU time:", \
1450
            reductionsFullTime/reductionsCount
1451
    print "Number of resultants computation rounds:", \
1452
        resultantsComputationsCount
1453
    print "Total CPU time spent in resultants computation rounds:", \
1454
        resultantsComputationsFullTime
1455
    if resultantsComputationsCount != 0:
1456
        print "Average resultants computation round CPU time:", \
1457
            resultantsComputationsFullTime/resultantsComputationsCount
1458
    print "Number of root finding rounds:", rootsComputationsCount
1459
    print "Total CPU time spent in roots finding rounds:", \
1460
        rootsComputationsFullTime
1461
    if rootsComputationsCount != 0:
1462
        print "Average roots finding round CPU time:", \
1463
            rootsComputationsFullTime/rootsComputationsCount
1464
    print "Global Wall time:", globalWallTime
1465
    print "Global CPU time:", globalCpuTime
1466
    ## Output counters
1467
# End srs_runSLZ-v02
1468

    
1469
def srs_run_SLZ_v03(inputFunction,
1470
                    inputLowerBound,
1471
                    inputUpperBound,
1472
                    alpha,
1473
                    degree,
1474
                    precision,
1475
                    emin,
1476
                    emax,
1477
                    targetHardnessToRound,
1478
                    debug = False):
1479
    """
1480
    Changes from V2:
1481
        Root search is changed:
1482
            - we compute the resultants in i and in t;
1483
            - we compute the roots set of each of these resultants;
1484
            - we combine all the possible pairs between the two sets;
1485
            - we check these pairs in polynomials for correctness.
1486
    Changes from V1: 
1487
        1- check for roots as soon as a resultant is computed;
1488
        2- once a non null resultant is found, check for roots;
1489
        3- constant resultant == no root.
1490
    """
1491

    
1492
    if debug:
1493
        print "Function                :", inputFunction
1494
        print "Lower bound             :", inputLowerBound
1495
        print "Upper bounds            :", inputUpperBound
1496
        print "Alpha                   :", alpha
1497
        print "Degree                  :", degree
1498
        print "Precision               :", precision
1499
        print "Emin                    :", emin
1500
        print "Emax                    :", emax
1501
        print "Target hardness-to-round:", targetHardnessToRound
1502
        print
1503
    ## Important constants.
1504
    ### Stretch the interval if no error happens.
1505
    noErrorIntervalStretch = 1 + 2^(-5)
1506
    ### If no vector validates the Coppersmith condition, shrink the interval
1507
    #   by the following factor.
1508
    noCoppersmithIntervalShrink = 1/2
1509
    ### If only (or at least) one vector validates the Coppersmith condition, 
1510
    #   shrink the interval by the following factor.
1511
    oneCoppersmithIntervalShrink = 3/4
1512
    #### If only null resultants are found, shrink the interval by the 
1513
    #    following factor.
1514
    onlyNullResultantsShrink     = 3/4
1515
    ## Structures.
1516
    RRR         = RealField(precision)
1517
    RRIF        = RealIntervalField(precision)
1518
    ## Converting input bound into the "right" field.
1519
    lowerBound = RRR(inputLowerBound)
1520
    upperBound = RRR(inputUpperBound)
1521
    ## Before going any further, check domain and image binade conditions.
1522
    print inputFunction(1).n()
1523
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
1524
    if output is None:
1525
        print "Invalid domain/image binades. Domain:",\
1526
        lowerBound, upperBound, "Images:", \
1527
        inputFunction(lowerBound), inputFunction(upperBound)
1528
        raise Exception("Invalid domain/image binades.")
1529
    lb = output[0] ; ub = output[1]
1530
    if lb != lowerBound or ub != upperBound:
1531
        print "lb:", lb, " - ub:", ub
1532
        print "Invalid domain/image binades. Domain:",\
1533
        lowerBound, upperBound, "Images:", \
1534
        inputFunction(lowerBound), inputFunction(upperBound)
1535
        raise Exception("Invalid domain/image binades.")
1536
    #
1537
    ## Progam initialization
1538
    ### Approximation polynomial accuracy and hardness to round.
1539
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
1540
    polyTargetHardnessToRound = targetHardnessToRound + 1
1541
    ### Significand to integer conversion ratio.
1542
    toIntegerFactor           = 2^(precision-1)
1543
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
1544
    ### Variables and rings for polynomials and root searching.
1545
    i=var('i')
1546
    t=var('t')
1547
    inputFunctionVariable = inputFunction.variables()[0]
1548
    function = inputFunction.subs({inputFunctionVariable:i})
1549
    #  Polynomial Rings over the integers, for root finding.
1550
    Zi = ZZ[i]
1551
    Zt = ZZ[t]
1552
    Zit = ZZ[i,t]
1553
    ## Number of iterations limit.
1554
    maxIter = 100000
1555
    #
1556
    ## Compute the scaled function and the degree, in their Sollya version 
1557
    #  once for all.
1558
    (scaledf, sdlb, sdub, silb, siub) = \
1559
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
1560
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
1561
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
1562
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
1563
    #
1564
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
1565
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
1566
    (unscalingFunction, scalingFunction) = \
1567
        slz_interval_scaling_expression(domainBoundsInterval, i)
1568
    #print scalingFunction, unscalingFunction
1569
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
1570
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
1571
    if internalSollyaPrec < 192:
1572
        internalSollyaPrec = 192
1573
    pobyso_set_prec_sa_so(internalSollyaPrec)
1574
    print "Sollya internal precision:", internalSollyaPrec
1575
    ## Some variables.
1576
    ### General variables
1577
    lb                  = sdlb
1578
    ub                  = sdub
1579
    nbw                 = 0
1580
    intervalUlp         = ub.ulp()
1581
    #### Will be set by slz_interval_and_polynomila_to_sage.
1582
    ic                  = 0 
1583
    icAsInt             = 0    # Set from ic.
1584
    solutionsSet        = set()
1585
    tsErrorWidth        = []
1586
    csErrorVectors      = []
1587
    csVectorsResultants = []
1588
    floatP              = 0  # Taylor polynomial.
1589
    floatPcv            = 0  # Ditto with variable change.
1590
    intvl               = "" # Taylor interval
1591
    terr                = 0  # Taylor error.
1592
    iterCount = 0
1593
    htrnSet = set()
1594
    ### Timers and counters.
1595
    wallTimeStart                   = 0
1596
    cpuTimeStart                    = 0
1597
    taylCondFailedCount             = 0
1598
    coppCondFailedCount             = 0
1599
    resultCondFailedCount           = 0
1600
    coppCondFailed                  = False
1601
    resultCondFailed                = False
1602
    globalResultsList               = []
1603
    basisConstructionsCount         = 0
1604
    basisConstructionsFullTime      = 0
1605
    basisConstructionTime           = 0
1606
    reductionsCount                 = 0
1607
    reductionsFullTime              = 0
1608
    reductionTime                   = 0
1609
    resultantsComputationsCount     = 0
1610
    resultantsComputationsFullTime  = 0
1611
    resultantsComputationTime       = 0
1612
    rootsComputationsCount          = 0
1613
    rootsComputationsFullTime       = 0
1614
    rootsComputationTime            = 0
1615
    print
1616
    ## Global times are started here.
1617
    wallTimeStart                   = walltime()
1618
    cpuTimeStart                    = cputime()
1619
    ## Main loop.
1620
    while True:
1621
        if lb >= sdub:
1622
            print "Lower bound reached upper bound."
1623
            break
1624
        if iterCount == maxIter:
1625
            print "Reached maxIter. Aborting"
1626
            break
1627
        iterCount += 1
1628
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
1629
            "log2(numbers)." 
1630
        ### Compute a Sollya polynomial that will honor the Taylor condition.
1631
        prceSo = slz_compute_polynomial_and_interval(scaledfSo,
1632
                                                     degreeSo,
1633
                                                     lb,
1634
                                                     ub,
1635
                                                     polyApproxAccur)
1636
        ### Convert back the data into Sage space.                         
1637
        (floatP, floatPcv, intvl, ic, terr) = \
1638
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
1639
                                                 prceSo[1], prceSo[2], 
1640
                                                 prceSo[3]))
1641
        intvl = RRIF(intvl)
1642
        ## Clean-up Sollya stuff.
1643
        for elem in prceSo:
1644
            sollya_lib_clear_obj(elem)
1645
        #print  floatP, floatPcv, intvl, ic, terr
1646
        #print floatP
1647
        #print intvl.endpoints()[0].n(), \
1648
        #      ic.n(),
1649
        #intvl.endpoints()[1].n()
1650
        ### Check returned data.
1651
        #### Is approximation error OK?
1652
        if terr > polyApproxAccur:
1653
            exceptionErrorMess  = \
1654
                "Approximation failed - computed error:" + \
1655
                str(terr) + " - target error: "
1656
            exceptionErrorMess += \
1657
                str(polyApproxAccur) + ". Aborting!"
1658
            raise Exception(exceptionErrorMess)
1659
        #### Is lower bound OK?
1660
        if lb != intvl.endpoints()[0]:
1661
            exceptionErrorMess =  "Wrong lower bound:" + \
1662
                               str(lb) + ". Aborting!"
1663
            raise Exception(exceptionErrorMess)
1664
        #### Set upper bound.
1665
        if ub > intvl.endpoints()[1]:
1666
            ub = intvl.endpoints()[1]
1667
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
1668
            "log2(numbers)." 
1669
            taylCondFailedCount += 1
1670
        #### Is interval not degenerate?
1671
        if lb >= ub:
1672
            exceptionErrorMess = "Degenerate interval: " + \
1673
                                "lowerBound(" + str(lb) +\
1674
                                ")>= upperBound(" + str(ub) + \
1675
                                "). Aborting!"
1676
            raise Exception(exceptionErrorMess)
1677
        #### Is interval center ok?
1678
        if ic <= lb or ic >= ub:
1679
            exceptionErrorMess =  "Invalid interval center for " + \
1680
                                str(lb) + ',' + str(ic) + ',' +  \
1681
                                str(ub) + ". Aborting!"
1682
            raise Exception(exceptionErrorMess)
1683
        ##### Current interval width and reset future interval width.
1684
        bw = ub - lb
1685
        nbw = 0
1686
        icAsInt = int(ic * toIntegerFactor)
1687
        #### The following ratio is always >= 1. In case we may want to
1688
        #    enlarge the interval
1689
        curTaylErrRat = polyApproxAccur / terr
1690
        ### Make the  integral transformations.
1691
        #### Bounds and interval center.
1692
        intIc = int(ic * toIntegerFactor)
1693
        intLb = int(lb * toIntegerFactor) - intIc
1694
        intUb = int(ub * toIntegerFactor) - intIc
1695
        #
1696
        #### Polynomials
1697
        basisConstructionTime         = cputime()
1698
        ##### To a polynomial with rational coefficients with rational arguments
1699
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
1700
        ##### To a polynomial with rational coefficients with integer arguments
1701
        ratIntP = \
1702
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
1703
        #####  Ultimately a multivariate polynomial with integer coefficients  
1704
        #      with integer arguments.
1705
        coppersmithTuple = \
1706
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
1707
                                                        precision, 
1708
                                                        targetHardnessToRound, 
1709
                                                        i, t)
1710
        #### Recover Coppersmith information.
1711
        intIntP = coppersmithTuple[0]
1712
        N = coppersmithTuple[1]
1713
        nAtAlpha = N^alpha
1714
        tBound = coppersmithTuple[2]
1715
        leastCommonMultiple = coppersmithTuple[3]
1716
        iBound = max(abs(intLb),abs(intUb))
1717
        basisConstructionsFullTime        += cputime(basisConstructionTime)
1718
        basisConstructionsCount           += 1
1719
        reductionTime                     = cputime()
1720
        #### Compute the reduced polynomials.
1721
        ccReducedPolynomialsList =  \
1722
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
1723
                                                            alpha, 
1724
                                                            N, 
1725
                                                            iBound, 
1726
                                                            tBound)
1727
        if ccReducedPolynomialsList is None:
1728
            raise Exception("Reduction failed.")
1729
        reductionsFullTime    += cputime(reductionTime)
1730
        reductionsCount       += 1
1731
        if len(ccReducedPolynomialsList) < 2:
1732
            print "Nothing to form resultants with."
1733
            print
1734
            coppCondFailedCount += 1
1735
            coppCondFailed = True
1736
            ##### Apply a different shrink factor according to 
1737
            #  the number of compliant polynomials.
1738
            if len(ccReducedPolynomialsList) == 0:
1739
                ub = lb + bw * noCoppersmithIntervalShrink
1740
            else: # At least one compliant polynomial.
1741
                ub = lb + bw * oneCoppersmithIntervalShrink
1742
            if ub > sdub:
1743
                ub = sdub
1744
            if lb == ub:
1745
                raise Exception("Cant shrink interval \
1746
                anymore to get Coppersmith condition.")
1747
            nbw = 0
1748
            continue
1749
        #### We have at least two polynomials.
1750
        #    Let us try to compute resultants.
1751
        #    For each resultant computed, go for the solutions.
1752
        ##### Build the pairs list.
1753
        polyPairsList           = []
1754
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
1755
            for polyInnerIndex in xrange(polyOuterIndex+1, 
1756
                                         len(ccReducedPolynomialsList)):
1757
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
1758
                                      ccReducedPolynomialsList[polyInnerIndex]))
1759
        #### Actual root search.
1760
        rootsSet            = set()
1761
        hasNonNullResultant = False
1762
        for polyPair in polyPairsList:
1763
            if hasNonNullResultant:
1764
                break
1765
            resultantsComputationTime   = cputime()
1766
            currentResultantI = \
1767
                slz_resultant(polyPair[0],
1768
                              polyPair[1],
1769
                              t)
1770
            resultantsComputationsCount    += 1
1771
            if currentResultantI is None:
1772
                resultantsComputationsFullTime +=  \
1773
                    cputime(resultantsComputationTime)
1774
                print "Nul resultant"
1775
                continue # Next polyPair.
1776
            currentResultantT = \
1777
                slz_resultant(polyPair[0],
1778
                              polyPair[1],
1779
                              i)
1780
            resultantsComputationsFullTime += cputime(resultantsComputationTime)
1781
            resultantsComputationsCount    += 1
1782
            if currentResultantT is None:                    
1783
                print "Nul resultant"
1784
                continue # Next polyPair.
1785
            else:
1786
                hasNonNullResultant = True
1787
            #### We have a non null resultants pair. From now on, whatever the
1788
            #    root search yields, no extra root search is necessary.
1789
            #### A constant resultant leads to no root. Root search is done.
1790
            if currentResultantI.degree() < 1:
1791
                print "Resultant is constant:", currentResultantI
1792
                break # Next polyPair and should break.
1793
            if currentResultantT.degree() < 1:
1794
                print "Resultant is constant:", currentResultantT
1795
                break # Next polyPair and should break.
1796
            #### Actual roots computation.
1797
            rootsComputationTime       = cputime()
1798
            ##### Compute i roots
1799
            iRootsList = Zi(currentResultantI).roots()
1800
            rootsComputationsCount      +=  1
1801
            if len(iRootsList) == 0:
1802
                rootsComputationsFullTime   =   cputime(rootsComputationTime)
1803
                print "No roots in \"i\"."
1804
                break # No roots in i.
1805
            tRootsList = Zt(currentResultantT).roots()
1806
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
1807
            rootsComputationsCount      +=  1
1808
            if len(tRootsList) == 0:
1809
                print "No roots in \"t\"."
1810
                break # No roots in i.
1811
            ##### For each iRoot, get a tRoot and check against the polynomials.
1812
            for iRoot in iRootsList:
1813
                ####### Roots returned by roots() are (value, multiplicity) 
1814
                #       tuples.
1815
                #print "iRoot:", iRoot
1816
                for tRoot in tRootsList:
1817
                ###### Use the tRoot against each polynomial, alternatively.
1818
                    if polyPair[0](iRoot[0],tRoot[0]) != 0:
1819
                        continue
1820
                    if polyPair[1](iRoot[0],tRoot[0]) != 0:
1821
                        continue
1822
                    rootsSet.add((iRoot[0], tRoot[0]))
1823
            # End of roots computation.
1824
        # End loop for polyPair in polyParsList.  Will break at next iteration.
1825
        # since a non null resultant was found.
1826
        #### Prepare for results for the current interval..
1827
        intervalResultsList = []
1828
        intervalResultsList.append((lb, ub))
1829
        #### Check roots.
1830
        rootsResultsList = []
1831
        for root in rootsSet:
1832
            specificRootResultsList = []
1833
            failingBounds = []
1834
            intIntPdivN = intIntP(root[0], root[1]) / N
1835
            if int(intIntPdivN) != intIntPdivN:
1836
                continue # Next root
1837
            # Root qualifies for modular equation, test it for hardness to round.
1838
            hardToRoundCaseAsFloat = RRR((icAsInt + root[0]) / toIntegerFactor)
1839
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
1840
            #print scalingFunction
1841
            scaledHardToRoundCaseAsFloat = \
1842
                scalingFunction(hardToRoundCaseAsFloat) 
1843
            print "Candidate HTRNc at x =", \
1844
                scaledHardToRoundCaseAsFloat.n().str(base=2),
1845
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
1846
                           function,
1847
                           2^-(targetHardnessToRound),
1848
                           RRR):
1849
                print hardToRoundCaseAsFloat, "is HTRN case."
1850
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
1851
                    print "Found in interval."
1852
                else:
1853
                    print "Found out of interval."
1854
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
1855
                # Check the root is in the bounds
1856
                if abs(root[0]) > iBound or abs(root[1]) > tBound:
1857
                    print "Root", root, "is out of bounds for modular equation."
1858
                    if abs(root[0]) > iBound:
1859
                        print "root[0]:", root[0]
1860
                        print "i bound:", iBound
1861
                        failingBounds.append('i')
1862
                        failingBounds.append(root[0])
1863
                        failingBounds.append(iBound)
1864
                    if abs(root[1]) > tBound:
1865
                        print "root[1]:", root[1]
1866
                        print "t bound:", tBound
1867
                        failingBounds.append('t')
1868
                        failingBounds.append(root[1])
1869
                        failingBounds.append(tBound)
1870
                if len(failingBounds) > 0:
1871
                    specificRootResultsList.append(failingBounds)
1872
            else: # From slz_is_htrn...
1873
                print "is not an HTRN case."
1874
            if len(specificRootResultsList) > 0:
1875
                rootsResultsList.append(specificRootResultsList)
1876
        if len(rootsResultsList) > 0:
1877
            intervalResultsList.append(rootsResultsList)
1878
        ### Check if a non null resultant was found. If not shrink the interval.
1879
        if not hasNonNullResultant:
1880
            print "Only null resultants for this reduction, shrinking interval."
1881
            resultCondFailed      =  True
1882
            resultCondFailedCount += 1
1883
            ### Shrink interval for next iteration.
1884
            ub = lb + bw * onlyNullResultantsShrink
1885
            if ub > sdub:
1886
                ub = sdub
1887
            nbw = 0
1888
            continue
1889
        #### An intervalResultsList has at least the bounds.
1890
        globalResultsList.append(intervalResultsList)   
1891
        #### Compute an incremented width for next upper bound, only
1892
        #    if not Coppersmith condition nor resultant condition
1893
        #    failed at the previous run. 
1894
        if not coppCondFailed and not resultCondFailed:
1895
            nbw = noErrorIntervalStretch * bw
1896
        else:
1897
            nbw = bw
1898
        ##### Reset the failure flags. They will be raised
1899
        #     again if needed.
1900
        coppCondFailed   = False
1901
        resultCondFailed = False
1902
        #### For next iteration (at end of loop)
1903
        #print "nbw:", nbw
1904
        lb  = ub
1905
        ub += nbw     
1906
        if ub > sdub:
1907
            ub = sdub
1908
        print
1909
    # End while True
1910
    ## Main loop just ended.
1911
    globalWallTime = walltime(wallTimeStart)
1912
    globalCpuTime  = cputime(cpuTimeStart)
1913
    ## Output results
1914
    print ; print "Intervals and HTRNs" ; print
1915
    for intervalResultsList in globalResultsList:
1916
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
1917
                               "," + str(intervalResultsList[0][1])  + "]"
1918
        print intervalResultString,
1919
        if len(intervalResultsList) > 1:
1920
            rootsResultsList = intervalResultsList[1]
1921
            specificRootResultIndex = 0
1922
            for specificRootResultsList in rootsResultsList:
1923
                if specificRootResultIndex == 0:
1924
                    print "\t", specificRootResultsList[0],
1925
                else:
1926
                    print " " * len(intervalResultString), "\t", \
1927
                          specificRootResultsList[0],
1928
                if len(specificRootResultsList) > 1:
1929
                    print specificRootResultsList[1]
1930
                specificRootResultIndex += 1
1931
        print ; print
1932
    #print globalResultsList
1933
    #
1934
    print "Timers and counters"
1935
    print
1936
    print "Number of iterations:", iterCount
1937
    print "Taylor condition failures:", taylCondFailedCount
1938
    print "Coppersmith condition failures:", coppCondFailedCount
1939
    print "Resultant condition failures:", resultCondFailedCount
1940
    print "Iterations count: ", iterCount
1941
    print "Number of intervals:", len(globalResultsList)
1942
    print "Number of basis constructions:", basisConstructionsCount 
1943
    print "Total CPU time spent in basis constructions:", \
1944
        basisConstructionsFullTime
1945
    if basisConstructionsCount != 0:
1946
        print "Average basis construction CPU time:", \
1947
            basisConstructionsFullTime/basisConstructionsCount
1948
    print "Number of reductions:", reductionsCount
1949
    print "Total CPU time spent in reductions:", reductionsFullTime
1950
    if reductionsCount != 0:
1951
        print "Average reduction CPU time:", \
1952
            reductionsFullTime/reductionsCount
1953
    print "Number of resultants computation rounds:", \
1954
        resultantsComputationsCount
1955
    print "Total CPU time spent in resultants computation rounds:", \
1956
        resultantsComputationsFullTime
1957
    if resultantsComputationsCount != 0:
1958
        print "Average resultants computation round CPU time:", \
1959
            resultantsComputationsFullTime/resultantsComputationsCount
1960
    print "Number of root finding rounds:", rootsComputationsCount
1961
    print "Total CPU time spent in roots finding rounds:", \
1962
        rootsComputationsFullTime
1963
    if rootsComputationsCount != 0:
1964
        print "Average roots finding round CPU time:", \
1965
            rootsComputationsFullTime/rootsComputationsCount
1966
    print "Global Wall time:", globalWallTime
1967
    print "Global CPU time:", globalCpuTime
1968
    ## Output counters
1969
# End srs_runSLZ-v03
1970

    
1971
def srs_run_SLZ_v04(inputFunction,
1972
                    inputLowerBound,
1973
                    inputUpperBound,
1974
                    alpha,
1975
                    degree,
1976
                    precision,
1977
                    emin,
1978
                    emax,
1979
                    targetHardnessToRound,
1980
                    debug = False):
1981
    """
1982
    Changes from V3:
1983
        Root search is changed again:
1984
            - only resultants in i are computed;
1985
            - roots in i are searched for;
1986
            - if any, they are tested for hardness-to-round.
1987
    Changes from V2:
1988
        Root search is changed:
1989
            - we compute the resultants in i and in t;
1990
            - we compute the roots set of each of these resultants;
1991
            - we combine all the possible pairs between the two sets;
1992
            - we check these pairs in polynomials for correctness.
1993
    Changes from V1: 
1994
        1- check for roots as soon as a resultant is computed;
1995
        2- once a non null resultant is found, check for roots;
1996
        3- constant resultant == no root.
1997
    """
1998

    
1999
    if debug:
2000
        print "Function                :", inputFunction
2001
        print "Lower bound             :", inputLowerBound
2002
        print "Upper bounds            :", inputUpperBound
2003
        print "Alpha                   :", alpha
2004
        print "Degree                  :", degree
2005
        print "Precision               :", precision
2006
        print "Emin                    :", emin
2007
        print "Emax                    :", emax
2008
        print "Target hardness-to-round:", targetHardnessToRound
2009
        print
2010
    ## Important constants.
2011
    ### Stretch the interval if no error happens.
2012
    noErrorIntervalStretch = 1 + 2^(-5)
2013
    ### If no vector validates the Coppersmith condition, shrink the interval
2014
    #   by the following factor.
2015
    noCoppersmithIntervalShrink = 1/2
2016
    ### If only (or at least) one vector validates the Coppersmith condition, 
2017
    #   shrink the interval by the following factor.
2018
    oneCoppersmithIntervalShrink = 3/4
2019
    #### If only null resultants are found, shrink the interval by the 
2020
    #    following factor.
2021
    onlyNullResultantsShrink     = 3/4
2022
    ## Structures.
2023
    RRR         = RealField(precision)
2024
    RRIF        = RealIntervalField(precision)
2025
    ## Converting input bound into the "right" field.
2026
    lowerBound = RRR(inputLowerBound)
2027
    upperBound = RRR(inputUpperBound)
2028
    ## Before going any further, check domain and image binade conditions.
2029
    print inputFunction(1).n()
2030
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
2031
    if output is None:
2032
        print "Invalid domain/image binades. Domain:",\
2033
        lowerBound, upperBound, "Images:", \
2034
        inputFunction(lowerBound), inputFunction(upperBound)
2035
        raise Exception("Invalid domain/image binades.")
2036
    lb = output[0] ; ub = output[1]
2037
    if lb != lowerBound or ub != upperBound:
2038
        print "lb:", lb, " - ub:", ub
2039
        print "Invalid domain/image binades. Domain:",\
2040
        lowerBound, upperBound, "Images:", \
2041
        inputFunction(lowerBound), inputFunction(upperBound)
2042
        raise Exception("Invalid domain/image binades.")
2043
    #
2044
    ## Progam initialization
2045
    ### Approximation polynomial accuracy and hardness to round.
2046
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
2047
    polyTargetHardnessToRound = targetHardnessToRound + 1
2048
    ### Significand to integer conversion ratio.
2049
    toIntegerFactor           = 2^(precision-1)
2050
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
2051
    ### Variables and rings for polynomials and root searching.
2052
    i=var('i')
2053
    t=var('t')
2054
    inputFunctionVariable = inputFunction.variables()[0]
2055
    function = inputFunction.subs({inputFunctionVariable:i})
2056
    #  Polynomial Rings over the integers, for root finding.
2057
    Zi = ZZ[i]
2058
    Zt = ZZ[t]
2059
    Zit = ZZ[i,t]
2060
    ## Number of iterations limit.
2061
    maxIter = 100000
2062
    #
2063
    ## Compute the scaled function and the degree, in their Sollya version 
2064
    #  once for all.
2065
    (scaledf, sdlb, sdub, silb, siub) = \
2066
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
2067
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
2068
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
2069
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
2070
    #
2071
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
2072
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
2073
    (unscalingFunction, scalingFunction) = \
2074
        slz_interval_scaling_expression(domainBoundsInterval, i)
2075
    #print scalingFunction, unscalingFunction
2076
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
2077
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
2078
    if internalSollyaPrec < 192:
2079
        internalSollyaPrec = 192
2080
    pobyso_set_prec_sa_so(internalSollyaPrec)
2081
    print "Sollya internal precision:", internalSollyaPrec
2082
    ## Some variables.
2083
    ### General variables
2084
    lb                  = sdlb
2085
    ub                  = sdub
2086
    nbw                 = 0
2087
    intervalUlp         = ub.ulp()
2088
    #### Will be set by slz_interval_and_polynomila_to_sage.
2089
    ic                  = 0 
2090
    icAsInt             = 0    # Set from ic.
2091
    solutionsSet        = set()
2092
    tsErrorWidth        = []
2093
    csErrorVectors      = []
2094
    csVectorsResultants = []
2095
    floatP              = 0  # Taylor polynomial.
2096
    floatPcv            = 0  # Ditto with variable change.
2097
    intvl               = "" # Taylor interval
2098
    terr                = 0  # Taylor error.
2099
    iterCount = 0
2100
    htrnSet = set()
2101
    ### Timers and counters.
2102
    wallTimeStart                   = 0
2103
    cpuTimeStart                    = 0
2104
    taylCondFailedCount             = 0
2105
    coppCondFailedCount             = 0
2106
    resultCondFailedCount           = 0
2107
    coppCondFailed                  = False
2108
    resultCondFailed                = False
2109
    globalResultsList               = []
2110
    basisConstructionsCount         = 0
2111
    basisConstructionsFullTime      = 0
2112
    basisConstructionTime           = 0
2113
    reductionsCount                 = 0
2114
    reductionsFullTime              = 0
2115
    reductionTime                   = 0
2116
    resultantsComputationsCount     = 0
2117
    resultantsComputationsFullTime  = 0
2118
    resultantsComputationTime       = 0
2119
    rootsComputationsCount          = 0
2120
    rootsComputationsFullTime       = 0
2121
    rootsComputationTime            = 0
2122
    print
2123
    ## Global times are started here.
2124
    wallTimeStart                   = walltime()
2125
    cpuTimeStart                    = cputime()
2126
    ## Main loop.
2127
    while True:
2128
        if lb >= sdub:
2129
            print "Lower bound reached upper bound."
2130
            break
2131
        if iterCount == maxIter:
2132
            print "Reached maxIter. Aborting"
2133
            break
2134
        iterCount += 1
2135
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
2136
            "log2(numbers)." 
2137
        ### Compute a Sollya polynomial that will honor the Taylor condition.
2138
        prceSo = slz_compute_polynomial_and_interval(scaledfSo,
2139
                                                     degreeSo,
2140
                                                     lb,
2141
                                                     ub,
2142
                                                     polyApproxAccur)
2143
        ### Convert back the data into Sage space.                         
2144
        (floatP, floatPcv, intvl, ic, terr) = \
2145
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
2146
                                                 prceSo[1], prceSo[2], 
2147
                                                 prceSo[3]))
2148
        intvl = RRIF(intvl)
2149
        ## Clean-up Sollya stuff.
2150
        for elem in prceSo:
2151
            sollya_lib_clear_obj(elem)
2152
        #print  floatP, floatPcv, intvl, ic, terr
2153
        #print floatP
2154
        #print intvl.endpoints()[0].n(), \
2155
        #      ic.n(),
2156
        #intvl.endpoints()[1].n()
2157
        ### Check returned data.
2158
        #### Is approximation error OK?
2159
        if terr > polyApproxAccur:
2160
            exceptionErrorMess  = \
2161
                "Approximation failed - computed error:" + \
2162
                str(terr) + " - target error: "
2163
            exceptionErrorMess += \
2164
                str(polyApproxAccur) + ". Aborting!"
2165
            raise Exception(exceptionErrorMess)
2166
        #### Is lower bound OK?
2167
        if lb != intvl.endpoints()[0]:
2168
            exceptionErrorMess =  "Wrong lower bound:" + \
2169
                               str(lb) + ". Aborting!"
2170
            raise Exception(exceptionErrorMess)
2171
        #### Set upper bound.
2172
        if ub > intvl.endpoints()[1]:
2173
            ub = intvl.endpoints()[1]
2174
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
2175
            "log2(numbers)." 
2176
            taylCondFailedCount += 1
2177
        #### Is interval not degenerate?
2178
        if lb >= ub:
2179
            exceptionErrorMess = "Degenerate interval: " + \
2180
                                "lowerBound(" + str(lb) +\
2181
                                ")>= upperBound(" + str(ub) + \
2182
                                "). Aborting!"
2183
            raise Exception(exceptionErrorMess)
2184
        #### Is interval center ok?
2185
        if ic <= lb or ic >= ub:
2186
            exceptionErrorMess =  "Invalid interval center for " + \
2187
                                str(lb) + ',' + str(ic) + ',' +  \
2188
                                str(ub) + ". Aborting!"
2189
            raise Exception(exceptionErrorMess)
2190
        ##### Current interval width and reset future interval width.
2191
        bw = ub - lb
2192
        nbw = 0
2193
        icAsInt = int(ic * toIntegerFactor)
2194
        #### The following ratio is always >= 1. In case we may want to
2195
        #    enlarge the interval
2196
        curTaylErrRat = polyApproxAccur / terr
2197
        ### Make the  integral transformations.
2198
        #### Bounds and interval center.
2199
        intIc = int(ic * toIntegerFactor)
2200
        intLb = int(lb * toIntegerFactor) - intIc
2201
        intUb = int(ub * toIntegerFactor) - intIc
2202
        #
2203
        #### Polynomials
2204
        basisConstructionTime         = cputime()
2205
        ##### To a polynomial with rational coefficients with rational arguments
2206
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
2207
        ##### To a polynomial with rational coefficients with integer arguments
2208
        ratIntP = \
2209
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
2210
        #####  Ultimately a multivariate polynomial with integer coefficients  
2211
        #      with integer arguments.
2212
        coppersmithTuple = \
2213
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
2214
                                                        precision, 
2215
                                                        targetHardnessToRound, 
2216
                                                        i, t)
2217
        #### Recover Coppersmith information.
2218
        intIntP = coppersmithTuple[0]
2219
        N = coppersmithTuple[1]
2220
        nAtAlpha = N^alpha
2221
        tBound = coppersmithTuple[2]
2222
        leastCommonMultiple = coppersmithTuple[3]
2223
        iBound = max(abs(intLb),abs(intUb))
2224
        basisConstructionsFullTime        += cputime(basisConstructionTime)
2225
        basisConstructionsCount           += 1
2226
        reductionTime                     = cputime()
2227
        #### Compute the reduced polynomials.
2228
        ccReducedPolynomialsList =  \
2229
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
2230
                                                            alpha, 
2231
                                                            N, 
2232
                                                            iBound, 
2233
                                                            tBound)
2234
        if ccReducedPolynomialsList is None:
2235
            raise Exception("Reduction failed.")
2236
        reductionsFullTime    += cputime(reductionTime)
2237
        reductionsCount       += 1
2238
        if len(ccReducedPolynomialsList) < 2:
2239
            print "Nothing to form resultants with."
2240
            print
2241
            coppCondFailedCount += 1
2242
            coppCondFailed = True
2243
            ##### Apply a different shrink factor according to 
2244
            #  the number of compliant polynomials.
2245
            if len(ccReducedPolynomialsList) == 0:
2246
                ub = lb + bw * noCoppersmithIntervalShrink
2247
            else: # At least one compliant polynomial.
2248
                ub = lb + bw * oneCoppersmithIntervalShrink
2249
            if ub > sdub:
2250
                ub = sdub
2251
            if lb == ub:
2252
                raise Exception("Cant shrink interval \
2253
                anymore to get Coppersmith condition.")
2254
            nbw = 0
2255
            continue
2256
        #### We have at least two polynomials.
2257
        #    Let us try to compute resultants.
2258
        #    For each resultant computed, go for the solutions.
2259
        ##### Build the pairs list.
2260
        polyPairsList           = []
2261
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
2262
            for polyInnerIndex in xrange(polyOuterIndex+1, 
2263
                                         len(ccReducedPolynomialsList)):
2264
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
2265
                                      ccReducedPolynomialsList[polyInnerIndex]))
2266
        #### Actual root search.
2267
        iRootsSet           = set()
2268
        hasNonNullResultant = False
2269
        for polyPair in polyPairsList:
2270
            resultantsComputationTime   = cputime()
2271
            currentResultantI = \
2272
                slz_resultant(polyPair[0],
2273
                              polyPair[1],
2274
                              t)
2275
            resultantsComputationsCount    += 1
2276
            resultantsComputationsFullTime +=  \
2277
                cputime(resultantsComputationTime)
2278
            #### Function slz_resultant returns None both for None and O
2279
            #    resultants.
2280
            if currentResultantI is None:
2281
                print "Nul resultant"
2282
                continue # Next polyPair.
2283
            ## We deleted the currentResultantI computation.
2284
            #### We have a non null resultant. From now on, whatever this
2285
            #    root search yields, no extra root search is necessary.
2286
            hasNonNullResultant = True
2287
            #### A constant resultant leads to no root. Root search is done.
2288
            if currentResultantI.degree() < 1:
2289
                print "Resultant is constant:", currentResultantI
2290
                break # There is no root.
2291
            #### Actual iroots computation.
2292
            rootsComputationTime        = cputime()
2293
            iRootsList = Zi(currentResultantI).roots()
2294
            rootsComputationsCount      +=  1
2295
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
2296
            if len(iRootsList) == 0:
2297
                print "No roots in \"i\"."
2298
                break # No roots in i.
2299
            else:
2300
                for iRoot in iRootsList:
2301
                    # A root is given as a (value, multiplicity) tuple.
2302
                    iRootsSet.add(iRoot[0])
2303
        # End loop for polyPair in polyParsList. We only loop again if a 
2304
        # None or zero resultant is found.
2305
        #### Prepare for results for the current interval..
2306
        intervalResultsList = []
2307
        intervalResultsList.append((lb, ub))
2308
        #### Check roots.
2309
        rootsResultsList = []
2310
        for iRoot in iRootsSet:
2311
            specificRootResultsList = []
2312
            failingBounds           = []
2313
            # Root qualifies for modular equation, test it for hardness to round.
2314
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
2315
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
2316
            #print scalingFunction
2317
            scaledHardToRoundCaseAsFloat = \
2318
                scalingFunction(hardToRoundCaseAsFloat) 
2319
            print "Candidate HTRNc at x =", \
2320
                scaledHardToRoundCaseAsFloat.n().str(base=2),
2321
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
2322
                           function,
2323
                           2^-(targetHardnessToRound),
2324
                           RRR):
2325
                print hardToRoundCaseAsFloat, "is HTRN case."
2326
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
2327
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
2328
                    print "Found in interval."
2329
                else:
2330
                    print "Found out of interval."
2331
                # Check the i root is within the i bound.
2332
                if abs(iRoot) > iBound:
2333
                    print "IRoot", iRoot, "is out of bounds for modular equation."
2334
                    print "i bound:", iBound
2335
                    failingBounds.append('i')
2336
                    failingBounds.append(iRoot)
2337
                    failingBounds.append(iBound)
2338
                if len(failingBounds) > 0:
2339
                    specificRootResultsList.append(failingBounds)
2340
            else: # From slz_is_htrn...
2341
                print "is not an HTRN case."
2342
            if len(specificRootResultsList) > 0:
2343
                rootsResultsList.append(specificRootResultsList)
2344
        if len(rootsResultsList) > 0:
2345
            intervalResultsList.append(rootsResultsList)
2346
        ### Check if a non null resultant was found. If not shrink the interval.
2347
        if not hasNonNullResultant:
2348
            print "Only null resultants for this reduction, shrinking interval."
2349
            resultCondFailed      =  True
2350
            resultCondFailedCount += 1
2351
            ### Shrink interval for next iteration.
2352
            ub = lb + bw * onlyNullResultantsShrink
2353
            if ub > sdub:
2354
                ub = sdub
2355
            nbw = 0
2356
            continue
2357
        #### An intervalResultsList has at least the bounds.
2358
        globalResultsList.append(intervalResultsList)   
2359
        #### Compute an incremented width for next upper bound, only
2360
        #    if not Coppersmith condition nor resultant condition
2361
        #    failed at the previous run. 
2362
        if not coppCondFailed and not resultCondFailed:
2363
            nbw = noErrorIntervalStretch * bw
2364
        else:
2365
            nbw = bw
2366
        ##### Reset the failure flags. They will be raised
2367
        #     again if needed.
2368
        coppCondFailed   = False
2369
        resultCondFailed = False
2370
        #### For next iteration (at end of loop)
2371
        #print "nbw:", nbw
2372
        lb  = ub
2373
        ub += nbw     
2374
        if ub > sdub:
2375
            ub = sdub
2376
        print
2377
    # End while True
2378
    ## Main loop just ended.
2379
    globalWallTime = walltime(wallTimeStart)
2380
    globalCpuTime  = cputime(cpuTimeStart)
2381
    ## Output results
2382
    print ; print "Intervals and HTRNs" ; print
2383
    for intervalResultsList in globalResultsList:
2384
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
2385
                               "," + str(intervalResultsList[0][1])  + "]"
2386
        print intervalResultString,
2387
        if len(intervalResultsList) > 1:
2388
            rootsResultsList = intervalResultsList[1]
2389
            specificRootResultIndex = 0
2390
            for specificRootResultsList in rootsResultsList:
2391
                if specificRootResultIndex == 0:
2392
                    print "\t", specificRootResultsList[0],
2393
                else:
2394
                    print " " * len(intervalResultString), "\t", \
2395
                          specificRootResultsList[0],
2396
                if len(specificRootResultsList) > 1:
2397
                    print specificRootResultsList[1]
2398
                specificRootResultIndex += 1
2399
        print ; print
2400
    #print globalResultsList
2401
    #
2402
    print "Timers and counters"
2403
    print
2404
    print "Number of iterations:", iterCount
2405
    print "Taylor condition failures:", taylCondFailedCount
2406
    print "Coppersmith condition failures:", coppCondFailedCount
2407
    print "Resultant condition failures:", resultCondFailedCount
2408
    print "Iterations count: ", iterCount
2409
    print "Number of intervals:", len(globalResultsList)
2410
    print "Number of basis constructions:", basisConstructionsCount 
2411
    print "Total CPU time spent in basis constructions:", \
2412
        basisConstructionsFullTime
2413
    if basisConstructionsCount != 0:
2414
        print "Average basis construction CPU time:", \
2415
            basisConstructionsFullTime/basisConstructionsCount
2416
    print "Number of reductions:", reductionsCount
2417
    print "Total CPU time spent in reductions:", reductionsFullTime
2418
    if reductionsCount != 0:
2419
        print "Average reduction CPU time:", \
2420
            reductionsFullTime/reductionsCount
2421
    print "Number of resultants computation rounds:", \
2422
        resultantsComputationsCount
2423
    print "Total CPU time spent in resultants computation rounds:", \
2424
        resultantsComputationsFullTime
2425
    if resultantsComputationsCount != 0:
2426
        print "Average resultants computation round CPU time:", \
2427
            resultantsComputationsFullTime/resultantsComputationsCount
2428
    print "Number of root finding rounds:", rootsComputationsCount
2429
    print "Total CPU time spent in roots finding rounds:", \
2430
        rootsComputationsFullTime
2431
    if rootsComputationsCount != 0:
2432
        print "Average roots finding round CPU time:", \
2433
            rootsComputationsFullTime/rootsComputationsCount
2434
    print "Global Wall time:", globalWallTime
2435
    print "Global CPU time:", globalCpuTime
2436
    ## Output counters
2437
# End srs_runSLZ-v04
2438

    
2439
def srs_run_SLZ_v05(inputFunction,
2440
                    inputLowerBound,
2441
                    inputUpperBound,
2442
                    alpha,
2443
                    degree,
2444
                    precision,
2445
                    emin,
2446
                    emax,
2447
                    targetHardnessToRound,
2448
                    debug = False):
2449
    """
2450
    Changes from V4:
2451
        Approximation polynomial has coefficients rounded.
2452
    Changes from V3:
2453
        Root search is changed again:
2454
            - only resultants in i are computed;
2455
            - roots in i are searched for;
2456
            - if any, they are tested for hardness-to-round.
2457
    Changes from V2:
2458
        Root search is changed:
2459
            - we compute the resultants in i and in t;
2460
            - we compute the roots set of each of these resultants;
2461
            - we combine all the possible pairs between the two sets;
2462
            - we check these pairs in polynomials for correctness.
2463
    Changes from V1: 
2464
        1- check for roots as soon as a resultant is computed;
2465
        2- once a non null resultant is found, check for roots;
2466
        3- constant resultant == no root.
2467
    """
2468

    
2469
    if debug:
2470
        print "Function                :", inputFunction
2471
        print "Lower bound             :", inputLowerBound
2472
        print "Upper bounds            :", inputUpperBound
2473
        print "Alpha                   :", alpha
2474
        print "Degree                  :", degree
2475
        print "Precision               :", precision
2476
        print "Emin                    :", emin
2477
        print "Emax                    :", emax
2478
        print "Target hardness-to-round:", targetHardnessToRound
2479
        print
2480
    ## Important constants.
2481
    ### Stretch the interval if no error happens.
2482
    noErrorIntervalStretch = 1 + 2^(-5)
2483
    ### If no vector validates the Coppersmith condition, shrink the interval
2484
    #   by the following factor.
2485
    noCoppersmithIntervalShrink = 1/2
2486
    ### If only (or at least) one vector validates the Coppersmith condition, 
2487
    #   shrink the interval by the following factor.
2488
    oneCoppersmithIntervalShrink = 3/4
2489
    #### If only null resultants are found, shrink the interval by the 
2490
    #    following factor.
2491
    onlyNullResultantsShrink     = 3/4
2492
    ## Structures.
2493
    RRR         = RealField(precision)
2494
    RRIF        = RealIntervalField(precision)
2495
    ## Converting input bound into the "right" field.
2496
    lowerBound = RRR(inputLowerBound)
2497
    upperBound = RRR(inputUpperBound)
2498
    ## Before going any further, check domain and image binade conditions.
2499
    print inputFunction(1).n()
2500
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
2501
    if output is None:
2502
        print "Invalid domain/image binades. Domain:",\
2503
        lowerBound, upperBound, "Images:", \
2504
        inputFunction(lowerBound), inputFunction(upperBound)
2505
        raise Exception("Invalid domain/image binades.")
2506
    lb = output[0] ; ub = output[1]
2507
    if lb != lowerBound or ub != upperBound:
2508
        print "lb:", lb, " - ub:", ub
2509
        print "Invalid domain/image binades. Domain:",\
2510
        lowerBound, upperBound, "Images:", \
2511
        inputFunction(lowerBound), inputFunction(upperBound)
2512
        raise Exception("Invalid domain/image binades.")
2513
    #
2514
    ## Progam initialization
2515
    ### Approximation polynomial accuracy and hardness to round.
2516
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
2517
    polyTargetHardnessToRound = targetHardnessToRound + 1
2518
    ### Significand to integer conversion ratio.
2519
    toIntegerFactor           = 2^(precision-1)
2520
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
2521
    ### Variables and rings for polynomials and root searching.
2522
    i=var('i')
2523
    t=var('t')
2524
    inputFunctionVariable = inputFunction.variables()[0]
2525
    function = inputFunction.subs({inputFunctionVariable:i})
2526
    #  Polynomial Rings over the integers, for root finding.
2527
    Zi = ZZ[i]
2528
    Zt = ZZ[t]
2529
    Zit = ZZ[i,t]
2530
    ## Number of iterations limit.
2531
    maxIter = 100000
2532
    #
2533
    ## Compute the scaled function and the degree, in their Sollya version 
2534
    #  once for all.
2535
    (scaledf, sdlb, sdub, silb, siub) = \
2536
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
2537
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
2538
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
2539
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
2540
    #
2541
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
2542
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
2543
    (unscalingFunction, scalingFunction) = \
2544
        slz_interval_scaling_expression(domainBoundsInterval, i)
2545
    #print scalingFunction, unscalingFunction
2546
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
2547
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
2548
    if internalSollyaPrec < 192:
2549
        internalSollyaPrec = 192
2550
    pobyso_set_prec_sa_so(internalSollyaPrec)
2551
    print "Sollya internal precision:", internalSollyaPrec
2552
    ## Some variables.
2553
    ### General variables
2554
    lb                  = sdlb
2555
    ub                  = sdub
2556
    nbw                 = 0
2557
    intervalUlp         = ub.ulp()
2558
    #### Will be set by slz_interval_and_polynomila_to_sage.
2559
    ic                  = 0 
2560
    icAsInt             = 0    # Set from ic.
2561
    solutionsSet        = set()
2562
    tsErrorWidth        = []
2563
    csErrorVectors      = []
2564
    csVectorsResultants = []
2565
    floatP              = 0  # Taylor polynomial.
2566
    floatPcv            = 0  # Ditto with variable change.
2567
    intvl               = "" # Taylor interval
2568
    terr                = 0  # Taylor error.
2569
    iterCount = 0
2570
    htrnSet = set()
2571
    ### Timers and counters.
2572
    wallTimeStart                   = 0
2573
    cpuTimeStart                    = 0
2574
    taylCondFailedCount             = 0
2575
    coppCondFailedCount             = 0
2576
    resultCondFailedCount           = 0
2577
    coppCondFailed                  = False
2578
    resultCondFailed                = False
2579
    globalResultsList               = []
2580
    basisConstructionsCount         = 0
2581
    basisConstructionsFullTime      = 0
2582
    basisConstructionTime           = 0
2583
    reductionsCount                 = 0
2584
    reductionsFullTime              = 0
2585
    reductionTime                   = 0
2586
    resultantsComputationsCount     = 0
2587
    resultantsComputationsFullTime  = 0
2588
    resultantsComputationTime       = 0
2589
    rootsComputationsCount          = 0
2590
    rootsComputationsFullTime       = 0
2591
    rootsComputationTime            = 0
2592
    print
2593
    ## Global times are started here.
2594
    wallTimeStart                   = walltime()
2595
    cpuTimeStart                    = cputime()
2596
    ## Main loop.
2597
    while True:
2598
        if lb >= sdub:
2599
            print "Lower bound reached upper bound."
2600
            break
2601
        if iterCount == maxIter:
2602
            print "Reached maxIter. Aborting"
2603
            break
2604
        iterCount += 1
2605
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
2606
            "log2(numbers)." 
2607
        ### Compute a Sollya polynomial that will honor the Taylor condition.
2608
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
2609
                                                        degreeSo,
2610
                                                        lb,
2611
                                                        ub,
2612
                                                        polyApproxAccur)
2613
        if prceSo is None:
2614
            raise Exception("Could not compute an approximation polynomial.")
2615
        ### Convert back the data into Sage space.                         
2616
        (floatP, floatPcv, intvl, ic, terr) = \
2617
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
2618
                                                 prceSo[1], prceSo[2], 
2619
                                                 prceSo[3]))
2620
        intvl = RRIF(intvl)
2621
        ## Clean-up Sollya stuff.
2622
        for elem in prceSo:
2623
            sollya_lib_clear_obj(elem)
2624
        #print  floatP, floatPcv, intvl, ic, terr
2625
        #print floatP
2626
        #print intvl.endpoints()[0].n(), \
2627
        #      ic.n(),
2628
        #intvl.endpoints()[1].n()
2629
        ### Check returned data.
2630
        #### Is approximation error OK?
2631
        if terr > polyApproxAccur:
2632
            exceptionErrorMess  = \
2633
                "Approximation failed - computed error:" + \
2634
                str(terr) + " - target error: "
2635
            exceptionErrorMess += \
2636
                str(polyApproxAccur) + ". Aborting!"
2637
            raise Exception(exceptionErrorMess)
2638
        #### Is lower bound OK?
2639
        if lb != intvl.endpoints()[0]:
2640
            exceptionErrorMess =  "Wrong lower bound:" + \
2641
                               str(lb) + ". Aborting!"
2642
            raise Exception(exceptionErrorMess)
2643
        #### Set upper bound.
2644
        if ub > intvl.endpoints()[1]:
2645
            ub = intvl.endpoints()[1]
2646
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
2647
            "log2(numbers)." 
2648
            taylCondFailedCount += 1
2649
        #### Is interval not degenerate?
2650
        if lb >= ub:
2651
            exceptionErrorMess = "Degenerate interval: " + \
2652
                                "lowerBound(" + str(lb) +\
2653
                                ")>= upperBound(" + str(ub) + \
2654
                                "). Aborting!"
2655
            raise Exception(exceptionErrorMess)
2656
        #### Is interval center ok?
2657
        if ic <= lb or ic >= ub:
2658
            exceptionErrorMess =  "Invalid interval center for " + \
2659
                                str(lb) + ',' + str(ic) + ',' +  \
2660
                                str(ub) + ". Aborting!"
2661
            raise Exception(exceptionErrorMess)
2662
        ##### Current interval width and reset future interval width.
2663
        bw = ub - lb
2664
        nbw = 0
2665
        icAsInt = int(ic * toIntegerFactor)
2666
        #### The following ratio is always >= 1. In case we may want to
2667
        #    enlarge the interval
2668
        curTaylErrRat = polyApproxAccur / terr
2669
        ### Make the  integral transformations.
2670
        #### Bounds and interval center.
2671
        intIc = int(ic * toIntegerFactor)
2672
        intLb = int(lb * toIntegerFactor) - intIc
2673
        intUb = int(ub * toIntegerFactor) - intIc
2674
        #
2675
        #### Polynomials
2676
        basisConstructionTime         = cputime()
2677
        ##### To a polynomial with rational coefficients with rational arguments
2678
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
2679
        ##### To a polynomial with rational coefficients with integer arguments
2680
        ratIntP = \
2681
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
2682
        #####  Ultimately a multivariate polynomial with integer coefficients  
2683
        #      with integer arguments.
2684
        coppersmithTuple = \
2685
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
2686
                                                        precision, 
2687
                                                        targetHardnessToRound, 
2688
                                                        i, t)
2689
        #### Recover Coppersmith information.
2690
        intIntP = coppersmithTuple[0]
2691
        N = coppersmithTuple[1]
2692
        nAtAlpha = N^alpha
2693
        tBound = coppersmithTuple[2]
2694
        leastCommonMultiple = coppersmithTuple[3]
2695
        iBound = max(abs(intLb),abs(intUb))
2696
        basisConstructionsFullTime        += cputime(basisConstructionTime)
2697
        basisConstructionsCount           += 1
2698
        #### Compute the matrix to reduce for debug purpose. Otherwise
2699
        #    slz_compute_coppersmith_reduced_polynomials does the job
2700
        #    invisibly.
2701
        if debug:
2702
            matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
2703
                                                                alpha,
2704
                                                                N,
2705
                                                                iBound,
2706
                                                                tBound)
2707
            maxNorm     = 0
2708
            latticeSize = 0
2709
            matrixFile = file('/tmp/matrixToReduce.txt', 'w')
2710
            for row in matrixToReduce.rows():
2711
                currentNorm = row.norm()
2712
                if currentNorm > maxNorm:
2713
                    maxNorm = currentNorm
2714
                latticeSize += 1
2715
                for elem in row:
2716
                    matrixFile.write(elem.str(base=2) + ",")
2717
                matrixFile.write("\n")
2718
            #matrixFile.write(matrixToReduce.str(radix="2") + "\n")
2719
            matrixFile.close()
2720
            #### We use here binary length as defined in LLL princepts.
2721
            binaryLength = latticeSize * log(maxNorm)
2722
            print "Binary length:", binaryLength.n()
2723
            raise Exception("Deliberate stop here.")
2724
        # End if debug
2725
        reductionTime                     = cputime()
2726
        #### Compute the reduced polynomials.
2727
        ccReducedPolynomialsList =  \
2728
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
2729
                                                            alpha, 
2730
                                                            N, 
2731
                                                            iBound, 
2732
                                                            tBound)
2733
        if ccReducedPolynomialsList is None:
2734
            raise Exception("Reduction failed.")
2735
        reductionsFullTime    += cputime(reductionTime)
2736
        reductionsCount       += 1
2737
        if len(ccReducedPolynomialsList) < 2:
2738
            print "Nothing to form resultants with."
2739
            print
2740
            coppCondFailedCount += 1
2741
            coppCondFailed = True
2742
            ##### Apply a different shrink factor according to 
2743
            #  the number of compliant polynomials.
2744
            if len(ccReducedPolynomialsList) == 0:
2745
                ub = lb + bw * noCoppersmithIntervalShrink
2746
            else: # At least one compliant polynomial.
2747
                ub = lb + bw * oneCoppersmithIntervalShrink
2748
            if ub > sdub:
2749
                ub = sdub
2750
            if lb == ub:
2751
                raise Exception("Cant shrink interval \
2752
                anymore to get Coppersmith condition.")
2753
            nbw = 0
2754
            continue
2755
        #### We have at least two polynomials.
2756
        #    Let us try to compute resultants.
2757
        #    For each resultant computed, go for the solutions.
2758
        ##### Build the pairs list.
2759
        polyPairsList           = []
2760
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
2761
            for polyInnerIndex in xrange(polyOuterIndex+1, 
2762
                                         len(ccReducedPolynomialsList)):
2763
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
2764
                                      ccReducedPolynomialsList[polyInnerIndex]))
2765
        #### Actual root search.
2766
        iRootsSet           = set()
2767
        hasNonNullResultant = False
2768
        for polyPair in polyPairsList:
2769
            resultantsComputationTime   = cputime()
2770
            currentResultantI = \
2771
                slz_resultant(polyPair[0],
2772
                              polyPair[1],
2773
                              t)
2774
            resultantsComputationsCount    += 1
2775
            resultantsComputationsFullTime +=  \
2776
                cputime(resultantsComputationTime)
2777
            #### Function slz_resultant returns None both for None and O
2778
            #    resultants.
2779
            if currentResultantI is None:
2780
                print "Nul resultant"
2781
                continue # Next polyPair.
2782
            ## We deleted the currentResultantI computation.
2783
            #### We have a non null resultant. From now on, whatever this
2784
            #    root search yields, no extra root search is necessary.
2785
            hasNonNullResultant = True
2786
            #### A constant resultant leads to no root. Root search is done.
2787
            if currentResultantI.degree() < 1:
2788
                print "Resultant is constant:", currentResultantI
2789
                break # There is no root.
2790
            #### Actual iroots computation.
2791
            rootsComputationTime        = cputime()
2792
            iRootsList = Zi(currentResultantI).roots()
2793
            rootsComputationsCount      +=  1
2794
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
2795
            if len(iRootsList) == 0:
2796
                print "No roots in \"i\"."
2797
                break # No roots in i.
2798
            else:
2799
                for iRoot in iRootsList:
2800
                    # A root is given as a (value, multiplicity) tuple.
2801
                    iRootsSet.add(iRoot[0])
2802
        # End loop for polyPair in polyParsList. We only loop again if a 
2803
        # None or zero resultant is found.
2804
        #### Prepare for results for the current interval..
2805
        intervalResultsList = []
2806
        intervalResultsList.append((lb, ub))
2807
        #### Check roots.
2808
        rootsResultsList = []
2809
        for iRoot in iRootsSet:
2810
            specificRootResultsList = []
2811
            failingBounds           = []
2812
            # Root qualifies for modular equation, test it for hardness to round.
2813
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
2814
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
2815
            #print scalingFunction
2816
            scaledHardToRoundCaseAsFloat = \
2817
                scalingFunction(hardToRoundCaseAsFloat) 
2818
            print "Candidate HTRNc at x =", \
2819
                scaledHardToRoundCaseAsFloat.n().str(base=2),
2820
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
2821
                           function,
2822
                           2^-(targetHardnessToRound),
2823
                           RRR):
2824
                print hardToRoundCaseAsFloat, "is HTRN case."
2825
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
2826
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
2827
                    print "Found in interval."
2828
                else:
2829
                    print "Found out of interval."
2830
                # Check the i root is within the i bound.
2831
                if abs(iRoot) > iBound:
2832
                    print "IRoot", iRoot, "is out of bounds for modular equation."
2833
                    print "i bound:", iBound
2834
                    failingBounds.append('i')
2835
                    failingBounds.append(iRoot)
2836
                    failingBounds.append(iBound)
2837
                if len(failingBounds) > 0:
2838
                    specificRootResultsList.append(failingBounds)
2839
            else: # From slz_is_htrn...
2840
                print "is not an HTRN case."
2841
            if len(specificRootResultsList) > 0:
2842
                rootsResultsList.append(specificRootResultsList)
2843
        if len(rootsResultsList) > 0:
2844
            intervalResultsList.append(rootsResultsList)
2845
        ### Check if a non null resultant was found. If not shrink the interval.
2846
        if not hasNonNullResultant:
2847
            print "Only null resultants for this reduction, shrinking interval."
2848
            resultCondFailed      =  True
2849
            resultCondFailedCount += 1
2850
            ### Shrink interval for next iteration.
2851
            ub = lb + bw * onlyNullResultantsShrink
2852
            if ub > sdub:
2853
                ub = sdub
2854
            nbw = 0
2855
            continue
2856
        #### An intervalResultsList has at least the bounds.
2857
        globalResultsList.append(intervalResultsList)   
2858
        #### Compute an incremented width for next upper bound, only
2859
        #    if not Coppersmith condition nor resultant condition
2860
        #    failed at the previous run. 
2861
        if not coppCondFailed and not resultCondFailed:
2862
            nbw = noErrorIntervalStretch * bw
2863
        else:
2864
            nbw = bw
2865
        ##### Reset the failure flags. They will be raised
2866
        #     again if needed.
2867
        coppCondFailed   = False
2868
        resultCondFailed = False
2869
        #### For next iteration (at end of loop)
2870
        #print "nbw:", nbw
2871
        lb  = ub
2872
        ub += nbw     
2873
        if ub > sdub:
2874
            ub = sdub
2875
        print
2876
    # End while True
2877
    ## Main loop just ended.
2878
    globalWallTime = walltime(wallTimeStart)
2879
    globalCpuTime  = cputime(cpuTimeStart)
2880
    ## Output results
2881
    print ; print "Intervals and HTRNs" ; print
2882
    for intervalResultsList in globalResultsList:
2883
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
2884
                               "," + str(intervalResultsList[0][1])  + "]"
2885
        print intervalResultString,
2886
        if len(intervalResultsList) > 1:
2887
            rootsResultsList = intervalResultsList[1]
2888
            specificRootResultIndex = 0
2889
            for specificRootResultsList in rootsResultsList:
2890
                if specificRootResultIndex == 0:
2891
                    print "\t", specificRootResultsList[0],
2892
                else:
2893
                    print " " * len(intervalResultString), "\t", \
2894
                          specificRootResultsList[0],
2895
                if len(specificRootResultsList) > 1:
2896
                    print specificRootResultsList[1]
2897
                specificRootResultIndex += 1
2898
        print ; print
2899
    #print globalResultsList
2900
    #
2901
    print "Timers and counters"
2902
    print
2903
    print "Number of iterations:", iterCount
2904
    print "Taylor condition failures:", taylCondFailedCount
2905
    print "Coppersmith condition failures:", coppCondFailedCount
2906
    print "Resultant condition failures:", resultCondFailedCount
2907
    print "Iterations count: ", iterCount
2908
    print "Number of intervals:", len(globalResultsList)
2909
    print "Number of basis constructions:", basisConstructionsCount 
2910
    print "Total CPU time spent in basis constructions:", \
2911
        basisConstructionsFullTime
2912
    if basisConstructionsCount != 0:
2913
        print "Average basis construction CPU time:", \
2914
            basisConstructionsFullTime/basisConstructionsCount
2915
    print "Number of reductions:", reductionsCount
2916
    print "Total CPU time spent in reductions:", reductionsFullTime
2917
    if reductionsCount != 0:
2918
        print "Average reduction CPU time:", \
2919
            reductionsFullTime/reductionsCount
2920
    print "Number of resultants computation rounds:", \
2921
        resultantsComputationsCount
2922
    print "Total CPU time spent in resultants computation rounds:", \
2923
        resultantsComputationsFullTime
2924
    if resultantsComputationsCount != 0:
2925
        print "Average resultants computation round CPU time:", \
2926
            resultantsComputationsFullTime/resultantsComputationsCount
2927
    print "Number of root finding rounds:", rootsComputationsCount
2928
    print "Total CPU time spent in roots finding rounds:", \
2929
        rootsComputationsFullTime
2930
    if rootsComputationsCount != 0:
2931
        print "Average roots finding round CPU time:", \
2932
            rootsComputationsFullTime/rootsComputationsCount
2933
    print "Global Wall time:", globalWallTime
2934
    print "Global CPU time:", globalCpuTime
2935
    ## Output counters
2936
# End srs_runSLZ-v05
2937

    
2938
def srs_run_SLZ_v06(inputFunction,
2939
                    inputLowerBound,
2940
                    inputUpperBound,
2941
                    alpha,
2942
                    degree,
2943
                    precision,
2944
                    emin,
2945
                    emax,
2946
                    targetHardnessToRound,
2947
                    debug = True):
2948
    """
2949
    Changes from V5:
2950
        Very verbose
2951
    Changes from V4:
2952
        Approximation polynomial has coefficients rounded.
2953
    Changes from V3:
2954
        Root search is changed again:
2955
            - only resultants in i are computed;
2956
            - roots in i are searched for;
2957
            - if any, they are tested for hardness-to-round.
2958
    Changes from V2:
2959
        Root search is changed:
2960
            - we compute the resultants in i and in t;
2961
            - we compute the roots set of each of these resultants;
2962
            - we combine all the possible pairs between the two sets;
2963
            - we check these pairs in polynomials for correctness.
2964
    Changes from V1: 
2965
        1- check for roots as soon as a resultant is computed;
2966
        2- once a non null resultant is found, check for roots;
2967
        3- constant resultant == no root.
2968
    """
2969

    
2970
    if debug:
2971
        print "Function                :", inputFunction
2972
        print "Lower bound             :", inputLowerBound
2973
        print "Upper bounds            :", inputUpperBound
2974
        print "Alpha                   :", alpha
2975
        print "Degree                  :", degree
2976
        print "Precision               :", precision
2977
        print "Emin                    :", emin
2978
        print "Emax                    :", emax
2979
        print "Target hardness-to-round:", targetHardnessToRound
2980
        print
2981
    ## Important constants.
2982
    ### Stretch the interval if no error happens.
2983
    noErrorIntervalStretch = 1 + 2^(-5)
2984
    ### If no vector validates the Coppersmith condition, shrink the interval
2985
    #   by the following factor.
2986
    noCoppersmithIntervalShrink = 1/2
2987
    ### If only (or at least) one vector validates the Coppersmith condition, 
2988
    #   shrink the interval by the following factor.
2989
    oneCoppersmithIntervalShrink = 3/4
2990
    #### If only null resultants are found, shrink the interval by the 
2991
    #    following factor.
2992
    onlyNullResultantsShrink     = 3/4
2993
    ## Structures.
2994
    RRR         = RealField(precision)
2995
    RRIF        = RealIntervalField(precision)
2996
    ## Converting input bound into the "right" field.
2997
    lowerBound = RRR(inputLowerBound)
2998
    upperBound = RRR(inputUpperBound)
2999
    ## Before going any further, check domain and image binade conditions.
3000
    print inputFunction(1).n()
3001
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
3002
    if output is None:
3003
        print "Invalid domain/image binades. Domain:",\
3004
        lowerBound, upperBound, "Images:", \
3005
        inputFunction(lowerBound), inputFunction(upperBound)
3006
        raise Exception("Invalid domain/image binades.")
3007
    lb = output[0] ; ub = output[1]
3008
    if lb != lowerBound or ub != upperBound:
3009
        print "lb:", lb, " - ub:", ub
3010
        print "Invalid domain/image binades. Domain:",\
3011
        lowerBound, upperBound, "Images:", \
3012
        inputFunction(lowerBound), inputFunction(upperBound)
3013
        raise Exception("Invalid domain/image binades.")
3014
    #
3015
    ## Progam initialization
3016
    ### Approximation polynomial accuracy and hardness to round.
3017
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
3018
    polyTargetHardnessToRound = targetHardnessToRound + 1
3019
    ### Significand to integer conversion ratio.
3020
    toIntegerFactor           = 2^(precision-1)
3021
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
3022
    ### Variables and rings for polynomials and root searching.
3023
    i=var('i')
3024
    t=var('t')
3025
    inputFunctionVariable = inputFunction.variables()[0]
3026
    function = inputFunction.subs({inputFunctionVariable:i})
3027
    #  Polynomial Rings over the integers, for root finding.
3028
    Zi = ZZ[i]
3029
    ## Number of iterations limit.
3030
    maxIter = 100000
3031
    #
3032
    ## Compute the scaled function and the degree, in their Sollya version 
3033
    #  once for all.
3034
    (scaledf, sdlb, sdub, silb, siub) = \
3035
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
3036
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
3037
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
3038
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
3039
    #
3040
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
3041
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
3042
    (unscalingFunction, scalingFunction) = \
3043
        slz_interval_scaling_expression(domainBoundsInterval, i)
3044
    #print scalingFunction, unscalingFunction
3045
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
3046
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
3047
    if internalSollyaPrec < 192:
3048
        internalSollyaPrec = 192
3049
    pobyso_set_prec_sa_so(internalSollyaPrec)
3050
    print "Sollya internal precision:", internalSollyaPrec
3051
    targetPlusOnePrecRF       = RealField(RRR.prec()+1)
3052
    if internalSollyaPrec < 1024:
3053
        quasiExactRF              = RealField(1014)
3054
    else:
3055
        quasiExactRF              = RealField(internalSollyaPrec) 
3056
    ## Some variables.
3057
    ### General variables
3058
    lb                  = sdlb
3059
    ub                  = sdub
3060
    nbw                 = 0
3061
    intervalUlp         = ub.ulp()
3062
    #### Will be set by slz_interval_and_polynomila_to_sage.
3063
    ic                  = 0 
3064
    icAsInt             = 0    # Set from ic.
3065
    solutionsSet        = set()
3066
    tsErrorWidth        = []
3067
    csErrorVectors      = []
3068
    csVectorsResultants = []
3069
    floatP              = 0  # Taylor polynomial.
3070
    floatPcv            = 0  # Ditto with variable change.
3071
    intvl               = "" # Taylor interval
3072
    terr                = 0  # Taylor error.
3073
    iterCount = 0
3074
    htrnSet = set()
3075
    ### Timers and counters.
3076
    wallTimeStart                   = 0
3077
    cpuTimeStart                    = 0
3078
    taylCondFailedCount             = 0
3079
    coppCondFailedCount             = 0
3080
    resultCondFailedCount           = 0
3081
    coppCondFailed                  = False
3082
    resultCondFailed                = False
3083
    globalResultsList               = []
3084
    basisConstructionsCount         = 0
3085
    basisConstructionsFullTime      = 0
3086
    basisConstructionTime           = 0
3087
    reductionsCount                 = 0
3088
    reductionsFullTime              = 0
3089
    reductionTime                   = 0
3090
    resultantsComputationsCount     = 0
3091
    resultantsComputationsFullTime  = 0
3092
    resultantsComputationTime       = 0
3093
    rootsComputationsCount          = 0
3094
    rootsComputationsFullTime       = 0
3095
    rootsComputationTime            = 0
3096
    print
3097
    ## Global times are started here.
3098
    wallTimeStart                   = walltime()
3099
    cpuTimeStart                    = cputime()
3100
    ## Main loop.
3101
    while True:
3102
        if lb >= sdub:
3103
            print "Lower bound reached upper bound."
3104
            break
3105
        if iterCount == maxIter:
3106
            print "Reached maxIter. Aborting"
3107
            break
3108
        iterCount += 1
3109
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3110
            "log2(numbers)." 
3111
        ### Compute a Sollya polynomial that will honor the Taylor condition.
3112
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
3113
                                                        degreeSo,
3114
                                                        lb,
3115
                                                        ub,
3116
                                                        polyApproxAccur,
3117
                                                        debug=True)
3118
        if debug:
3119
            print "Sollya Taylor polynomial:", pobyso_autoprint(prceSo[0])
3120
            print "Sollya interval         :", pobyso_autoprint(prceSo[1])
3121
            print "Sollya interval center  :", pobyso_autoprint(prceSo[2])
3122
            print "Sollya Taylor error     :", pobyso_autoprint(prceSo[3])
3123

    
3124
        ### Convert back the data into Sage space.                         
3125
        (floatP, floatPcv, intvl, ic, terr) = \
3126
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
3127
                                                 prceSo[1], prceSo[2], 
3128
                                                 prceSo[3]))
3129
        intvl = RRIF(intvl)
3130
        ## Clean-up Sollya stuff.
3131
        for elem in prceSo:
3132
            sollya_lib_clear_obj(elem)
3133
        #print  floatP, floatPcv, intvl, ic, terr
3134
        #print floatP
3135
        #print intvl.endpoints()[0].n(), \
3136
        #      ic.n(),
3137
        #intvl.endpoints()[1].n()
3138
        ### Check returned data.
3139
        #### Is approximation error OK?
3140
        if terr > polyApproxAccur:
3141
            exceptionErrorMess  = \
3142
                "Approximation failed - computed error:" + \
3143
                str(terr) + " - target error: "
3144
            exceptionErrorMess += \
3145
                str(polyApproxAccur) + ". Aborting!"
3146
            raise Exception(exceptionErrorMess)
3147
        #### Is lower bound OK?
3148
        if lb != intvl.endpoints()[0]:
3149
            exceptionErrorMess =  "Wrong lower bound:" + \
3150
                               str(lb) + ". Aborting!"
3151
            raise Exception(exceptionErrorMess)
3152
        #### Set upper bound.
3153
        if ub > intvl.endpoints()[1]:
3154
            ub = intvl.endpoints()[1]
3155
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3156
            "log2(numbers)." 
3157
            taylCondFailedCount += 1
3158
        #### Is interval not degenerate?
3159
        if lb >= ub:
3160
            exceptionErrorMess = "Degenerate interval: " + \
3161
                                "lowerBound(" + str(lb) +\
3162
                                ")>= upperBound(" + str(ub) + \
3163
                                "). Aborting!"
3164
            raise Exception(exceptionErrorMess)
3165
        #### Is interval center ok?
3166
        if ic <= lb or ic >= ub:
3167
            exceptionErrorMess =  "Invalid interval center for " + \
3168
                                str(lb) + ',' + str(ic) + ',' +  \
3169
                                str(ub) + ". Aborting!"
3170
            raise Exception(exceptionErrorMess)
3171
        ##### Current interval width and reset future interval width.
3172
        bw = ub - lb
3173
        nbw = 0
3174
        icAsInt = int(ic * toIntegerFactor)
3175
        #### The following ratio is always >= 1. In case we may want to
3176
        #    enlarge the interval
3177
        curTaylErrRat = polyApproxAccur / terr
3178
        ### Make the  integral transformations.
3179
        #### Bounds and interval center.
3180
        intIc = int(ic * toIntegerFactor)
3181
        intLb = int(lb * toIntegerFactor) - intIc
3182
        intUb = int(ub * toIntegerFactor) - intIc
3183
        #
3184
        #### Polynomials
3185
        basisConstructionTime         = cputime()
3186
        ##### To a polynomial with rational coefficients with rational arguments
3187
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
3188
        if debug:
3189
            print "Polynomial: rational coefficients for rational argument:"
3190
            print ratRatP
3191
        ##### To a polynomial with rational coefficients with integer arguments
3192
        ratIntP = \
3193
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
3194
        if debug:
3195
            print "Polynomial: rational coefficients for integer argument:"
3196
            print ratIntP
3197
        #####  Ultimately a multivariate polynomial with integer coefficients  
3198
        #      with integer arguments.
3199
        coppersmithTuple = \
3200
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
3201
                                                        precision, 
3202
                                                        targetHardnessToRound, 
3203
                                                        i, t)
3204
        #### Recover Coppersmith information.
3205
        intIntP = coppersmithTuple[0]
3206
        N = coppersmithTuple[1]
3207
        nAtAlpha = N^alpha
3208
        tBound = coppersmithTuple[2]
3209
        leastCommonMultiple = coppersmithTuple[3]
3210
        iBound = max(abs(intLb),abs(intUb))
3211
        if debug:
3212
            print "Polynomial: integer coefficients for integer argument:"
3213
            print intIntP
3214
            print "N:", N
3215
            print "t bound:", tBound
3216
            print "i bound:", iBound
3217
            print "Least common multiple:", leastCommonMultiple
3218
        basisConstructionsFullTime        += cputime(basisConstructionTime)
3219
        basisConstructionsCount           += 1
3220
        """
3221
        #### Compute the matrix to reduce.
3222
        matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
3223
                                                            alpha,
3224
                                                            N,
3225
                                                            iBound,
3226
                                                            tBound)
3227
        matrixFile = file('/tmp/matrixToReduce.txt', 'w')
3228
        for row in matrixToReduce.rows():
3229
            matrixFile.write(str(row) + "\n")
3230
        matrixFile.close()
3231
        raise Exception("Deliberate stop here.")
3232
        """
3233
        reductionTime                     = cputime()
3234
        #### Compute the reduced polynomials.
3235
        ccReducedPolynomialsList =  \
3236
                slz_compute_coppersmith_reduced_polynomials(intIntP, 
3237
                                                            alpha, 
3238
                                                            N, 
3239
                                                            iBound, 
3240
                                                            tBound)
3241
        if ccReducedPolynomialsList is None:
3242
            raise Exception("Reduction failed.")
3243
        reductionsFullTime    += cputime(reductionTime)
3244
        reductionsCount       += 1
3245
        if len(ccReducedPolynomialsList) < 2:
3246
            print "Nothing to form resultants with."
3247
            print
3248
            coppCondFailedCount += 1
3249
            coppCondFailed = True
3250
            ##### Apply a different shrink factor according to 
3251
            #  the number of compliant polynomials.
3252
            if len(ccReducedPolynomialsList) == 0:
3253
                ub = lb + bw * noCoppersmithIntervalShrink
3254
            else: # At least one compliant polynomial.
3255
                ub = lb + bw * oneCoppersmithIntervalShrink
3256
            if ub > sdub:
3257
                ub = sdub
3258
            if lb == ub:
3259
                raise Exception("Cant shrink interval \
3260
                anymore to get Coppersmith condition.")
3261
            nbw = 0
3262
            continue
3263
        #### We have at least two polynomials.
3264
        #    Let us try to compute resultants.
3265
        #    For each resultant computed, go for the solutions.
3266
        ##### Build the pairs list.
3267
        polyPairsList           = []
3268
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
3269
            for polyInnerIndex in xrange(polyOuterIndex+1, 
3270
                                         len(ccReducedPolynomialsList)):
3271
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
3272
                                      ccReducedPolynomialsList[polyInnerIndex]))
3273
        #### Actual root search.
3274
        iRootsSet           = set()
3275
        hasNonNullResultant = False
3276
        for polyPair in polyPairsList:
3277
            resultantsComputationTime   = cputime()
3278
            currentResultantI = \
3279
                slz_resultant(polyPair[0],
3280
                              polyPair[1],
3281
                              t)
3282
            resultantsComputationsCount    += 1
3283
            resultantsComputationsFullTime +=  \
3284
                cputime(resultantsComputationTime)
3285
            #### Function slz_resultant returns None both for None and O
3286
            #    resultants.
3287
            if currentResultantI is None:
3288
                print "Nul resultant"
3289
                continue # Next polyPair.
3290
            ## We deleted the currentResultantI computation.
3291
            #### We have a non null resultant. From now on, whatever this
3292
            #    root search yields, no extra root search is necessary.
3293
            hasNonNullResultant = True
3294
            #### A constant resultant leads to no root. Root search is done.
3295
            if currentResultantI.degree() < 1:
3296
                print "Resultant is constant:", currentResultantI
3297
                break # There is no root.
3298
            #### Actual iroots computation.
3299
            rootsComputationTime        = cputime()
3300
            iRootsList = Zi(currentResultantI).roots()
3301
            rootsComputationsCount      +=  1
3302
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
3303
            if len(iRootsList) == 0:
3304
                print "No roots in \"i\"."
3305
                break # No roots in i.
3306
            else:
3307
                for iRoot in iRootsList:
3308
                    # A root is given as a (value, multiplicity) tuple.
3309
                    iRootsSet.add(iRoot[0])
3310
        # End loop for polyPair in polyParsList. We only loop again if a 
3311
        # None or zero resultant is found.
3312
        #### Prepare for results for the current interval..
3313
        intervalResultsList = []
3314
        intervalResultsList.append((lb, ub))
3315
        #### Check roots.
3316
        rootsResultsList = []
3317
        for iRoot in iRootsSet:
3318
            specificRootResultsList = []
3319
            failingBounds           = []
3320
            # Root qualifies for modular equation, test it for hardness to round.
3321
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
3322
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
3323
            #print scalingFunction
3324
            scaledHardToRoundCaseAsFloat = \
3325
                scalingFunction(hardToRoundCaseAsFloat) 
3326
            print "Candidate HTRNc at x =", \
3327
                scaledHardToRoundCaseAsFloat.n().str(base=2),
3328
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
3329
                           function,
3330
                           2^-(targetHardnessToRound),
3331
                           RRR,
3332
                           targetPlusOnePrecRF,
3333
                           quasiExactRF):
3334
                print hardToRoundCaseAsFloat, "is HTRN case."
3335
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
3336
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
3337
                    print "Found in interval."
3338
                else:
3339
                    print "Found out of interval."
3340
                # Check the i root is within the i bound.
3341
                if abs(iRoot) > iBound:
3342
                    print "IRoot", iRoot, "is out of bounds for modular equation."
3343
                    print "i bound:", iBound
3344
                    failingBounds.append('i')
3345
                    failingBounds.append(iRoot)
3346
                    failingBounds.append(iBound)
3347
                if len(failingBounds) > 0:
3348
                    specificRootResultsList.append(failingBounds)
3349
            else: # From slz_is_htrn...
3350
                print "is not an HTRN case."
3351
            if len(specificRootResultsList) > 0:
3352
                rootsResultsList.append(specificRootResultsList)
3353
        if len(rootsResultsList) > 0:
3354
            intervalResultsList.append(rootsResultsList)
3355
        ### Check if a non null resultant was found. If not shrink the interval.
3356
        if not hasNonNullResultant:
3357
            print "Only null resultants for this reduction, shrinking interval."
3358
            resultCondFailed      =  True
3359
            resultCondFailedCount += 1
3360
            ### Shrink interval for next iteration.
3361
            ub = lb + bw * onlyNullResultantsShrink
3362
            if ub > sdub:
3363
                ub = sdub
3364
            nbw = 0
3365
            continue
3366
        #### An intervalResultsList has at least the bounds.
3367
        globalResultsList.append(intervalResultsList)   
3368
        #### Compute an incremented width for next upper bound, only
3369
        #    if not Coppersmith condition nor resultant condition
3370
        #    failed at the previous run. 
3371
        if not coppCondFailed and not resultCondFailed:
3372
            nbw = noErrorIntervalStretch * bw
3373
        else:
3374
            nbw = bw
3375
        ##### Reset the failure flags. They will be raised
3376
        #     again if needed.
3377
        coppCondFailed   = False
3378
        resultCondFailed = False
3379
        #### For next iteration (at end of loop)
3380
        #print "nbw:", nbw
3381
        lb  = ub
3382
        ub += nbw     
3383
        if ub > sdub:
3384
            ub = sdub
3385
        print
3386
    # End while True
3387
    ## Main loop just ended.
3388
    globalWallTime = walltime(wallTimeStart)
3389
    globalCpuTime  = cputime(cpuTimeStart)
3390
    ## Output results
3391
    print ; print "Intervals and HTRNs" ; print
3392
    for intervalResultsList in globalResultsList:
3393
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
3394
                               "," + str(intervalResultsList[0][1])  + "]"
3395
        print intervalResultString,
3396
        if len(intervalResultsList) > 1:
3397
            rootsResultsList = intervalResultsList[1]
3398
            specificRootResultIndex = 0
3399
            for specificRootResultsList in rootsResultsList:
3400
                if specificRootResultIndex == 0:
3401
                    print "\t", specificRootResultsList[0],
3402
                else:
3403
                    print " " * len(intervalResultString), "\t", \
3404
                          specificRootResultsList[0],
3405
                if len(specificRootResultsList) > 1:
3406
                    print specificRootResultsList[1]
3407
                specificRootResultIndex += 1
3408
        print ; print
3409
    #print globalResultsList
3410
    #
3411
    print "Timers and counters"
3412
    print
3413
    print "Number of iterations:", iterCount
3414
    print "Taylor condition failures:", taylCondFailedCount
3415
    print "Coppersmith condition failures:", coppCondFailedCount
3416
    print "Resultant condition failures:", resultCondFailedCount
3417
    print "Iterations count: ", iterCount
3418
    print "Number of intervals:", len(globalResultsList)
3419
    print "Number of basis constructions:", basisConstructionsCount 
3420
    print "Total CPU time spent in basis constructions:", \
3421
        basisConstructionsFullTime
3422
    if basisConstructionsCount != 0:
3423
        print "Average basis construction CPU time:", \
3424
            basisConstructionsFullTime/basisConstructionsCount
3425
    print "Number of reductions:", reductionsCount
3426
    print "Total CPU time spent in reductions:", reductionsFullTime
3427
    if reductionsCount != 0:
3428
        print "Average reduction CPU time:", \
3429
            reductionsFullTime/reductionsCount
3430
    print "Number of resultants computation rounds:", \
3431
        resultantsComputationsCount
3432
    print "Total CPU time spent in resultants computation rounds:", \
3433
        resultantsComputationsFullTime
3434
    if resultantsComputationsCount != 0:
3435
        print "Average resultants computation round CPU time:", \
3436
            resultantsComputationsFullTime/resultantsComputationsCount
3437
    print "Number of root finding rounds:", rootsComputationsCount
3438
    print "Total CPU time spent in roots finding rounds:", \
3439
        rootsComputationsFullTime
3440
    if rootsComputationsCount != 0:
3441
        print "Average roots finding round CPU time:", \
3442
            rootsComputationsFullTime/rootsComputationsCount
3443
    print "Global Wall time:", globalWallTime
3444
    print "Global CPU time:", globalCpuTime
3445
    ## Output counters
3446
# End srs_runSLZ-v06