Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (107,6 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
        print "[", intervalResultsList[0][0], ",",intervalResultsList[0][1], "]",
460
        if len(intervalResultsList) > 1:
461
            rootsResultsList = intervalResultsList[1]
462
            for specificRootResultsList in rootsResultsList:
463
                print "\t", specificRootResultsList[0],
464
                if len(specificRootResultsList) > 1:
465
                    print specificRootResultsList[1],
466
        print ; print
467
    #print globalResultsList
468
    #
469
    print "Timers and counters"
470
    print
471
    print "Number of iterations:", iterCount
472
    print "Taylor condition failures:", taylCondFailedCount
473
    print "Coppersmith condition failures:", coppCondFailedCount
474
    print "Resultant condition failures:", resultCondFailedCount
475
    print "Iterations count: ", iterCount
476
    print "Number of intervals:", len(globalResultsList)
477
    print "Number of basis constructions:", basisConstructionsCount 
478
    print "Total CPU time spent in basis constructions:", \
479
        basisConstructionsFullTime
480
    if basisConstructionsCount != 0:
481
        print "Average basis construction CPU time:", \
482
            basisConstructionsFullTime/basisConstructionsCount
483
    print "Number of reductions:", reductionsCount
484
    print "Total CPU time spent in reductions:", reductionsFullTime
485
    if reductionsCount != 0:
486
        print "Average reduction CPU time:", \
487
            reductionsFullTime/reductionsCount
488
    print "Number of resultants computation rounds:", \
489
        resultantsComputationsCount
490
    print "Total CPU time spent in resultants computation rounds:", \
491
        resultantsComputationsFullTime
492
    if resultantsComputationsCount != 0:
493
        print "Average resultants computation round CPU time:", \
494
            resultantsComputationsFullTime/resultantsComputationsCount
495
    print "Number of root finding rounds:", rootsComputationsCount
496
    print "Total CPU time spent in roots finding rounds:", \
497
        rootsComputationsFullTime
498
    if rootsComputationsCount != 0:
499
        print "Average roots finding round CPU time:", \
500
            rootsComputationsFullTime/rootsComputationsCount
501
    print "Global Wall time:", globalWallTime
502
    print "Global CPU time:", globalCpuTime
503
    ## Output counters
504
# End srs_compute_lattice_volume
505
 
506
"""
507
SLZ runtime function.
508
"""
509

    
510
def srs_run_SLZ_v01(inputFunction,
511
                    inputLowerBound,
512
                    inputUpperBound,
513
                    alpha,
514
                    degree,
515
                    precision,
516
                    emin,
517
                    emax,
518
                    targetHardnessToRound,
519
                    debug = False):
520

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

    
970
def srs_run_SLZ_v02(inputFunction,
971
                    inputLowerBound,
972
                    inputUpperBound,
973
                    alpha,
974
                    degree,
975
                    precision,
976
                    emin,
977
                    emax,
978
                    targetHardnessToRound,
979
                    debug = False):
980
    """
981
    Changes from V1: 
982
        1- check for roots as soon as a resultant is computed;
983
        2- once a non null resultant is found, check for roots;
984
        3- constant resultant == no root.
985
    """
986

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

    
1445
def srs_run_SLZ_v03(inputFunction,
1446
                    inputLowerBound,
1447
                    inputUpperBound,
1448
                    alpha,
1449
                    degree,
1450
                    precision,
1451
                    emin,
1452
                    emax,
1453
                    targetHardnessToRound,
1454
                    debug = False):
1455
    """
1456
    Changes from V2:
1457
        Root search is changed:
1458
            - we compute the resultants in i and in t;
1459
            - we compute the roots set of each of these resultants;
1460
            - we combine all the possible pairs between the two sets;
1461
            - we check these pairs in polynomials for correctness.
1462
    Changes from V1: 
1463
        1- check for roots as soon as a resultant is computed;
1464
        2- once a non null resultant is found, check for roots;
1465
        3- constant resultant == no root.
1466
    """
1467

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

    
1939
def srs_run_SLZ_v04(inputFunction,
1940
                    inputLowerBound,
1941
                    inputUpperBound,
1942
                    alpha,
1943
                    degree,
1944
                    precision,
1945
                    emin,
1946
                    emax,
1947
                    targetHardnessToRound,
1948
                    debug = False):
1949
    """
1950
    Changes from V3:
1951
        Root search is changed again:
1952
            - only resultants in i are computed;
1953
            - root are searched for;
1954
            - if any, they are tested for hardness-to-round.
1955
    Changes from V2:
1956
        Root search is changed:
1957
            - we compute the resultants in i and in t;
1958
            - we compute the roots set of each of these resultants;
1959
            - we combine all the possible pairs between the two sets;
1960
            - we check these pairs in polynomials for correctness.
1961
    Changes from V1: 
1962
        1- check for roots as soon as a resultant is computed;
1963
        2- once a non null resultant is found, check for roots;
1964
        3- constant resultant == no root.
1965
    """
1966

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