Statistiques
| Révision :

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

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

    
522
def srs_run_SLZ_v01(inputFunction,
523
                    inputLowerBound,
524
                    inputUpperBound,
525
                    alpha,
526
                    degree,
527
                    precision,
528
                    emin,
529
                    emax,
530
                    targetHardnessToRound,
531
                    debug = False):
532

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

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

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

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

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

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

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

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

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

    
2989
    if debug:
2990
        print "Function                :", inputFunction
2991
        print "Lower bound             :", inputLowerBound
2992
        print "Upper bounds            :", inputUpperBound
2993
        print "Alpha                   :", alpha
2994
        print "Degree                  :", degree
2995
        print "Precision               :", precision
2996
        print "Emin                    :", emin
2997
        print "Emax                    :", emax
2998
        print "Target hardness-to-round:", targetHardnessToRound
2999
        print
3000
    ## Important constants.
3001
    ### Stretch the interval if no error happens.
3002
    noErrorIntervalStretch = 1 + 2^(-5)
3003
    ### If no vector validates the Coppersmith condition, shrink the interval
3004
    #   by the following factor.
3005
    noCoppersmithIntervalShrink = 1/2
3006
    ### If only (or at least) one vector validates the Coppersmith condition, 
3007
    #   shrink the interval by the following factor.
3008
    oneCoppersmithIntervalShrink = 3/4
3009
    #### If only null resultants are found, shrink the interval by the 
3010
    #    following factor.
3011
    onlyNullResultantsShrink     = 3/4
3012
    ## Structures.
3013
    RRR         = RealField(precision)
3014
    RRIF        = RealIntervalField(precision)
3015
    ## Converting input bound into the "right" field.
3016
    lowerBound = RRR(inputLowerBound)
3017
    upperBound = RRR(inputUpperBound)
3018
    ## Before going any further, check domain and image binade conditions.
3019
    print inputFunction(1).n()
3020
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
3021
    if output is None:
3022
        print "Invalid domain/image binades. Domain:",\
3023
        lowerBound, upperBound, "Images:", \
3024
        inputFunction(lowerBound), inputFunction(upperBound)
3025
        raise Exception("Invalid domain/image binades.")
3026
    lb = output[0] ; ub = output[1]
3027
    if lb != lowerBound or ub != upperBound:
3028
        print "lb:", lb, " - ub:", ub
3029
        print "Invalid domain/image binades. Domain:",\
3030
        lowerBound, upperBound, "Images:", \
3031
        inputFunction(lowerBound), inputFunction(upperBound)
3032
        raise Exception("Invalid domain/image binades.")
3033
    #
3034
    ## Progam initialization
3035
    ### Approximation polynomial accuracy and hardness to round.
3036
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
3037
    polyTargetHardnessToRound = targetHardnessToRound + 1
3038
    ### Significand to integer conversion ratio.
3039
    toIntegerFactor           = 2^(precision-1)
3040
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
3041
    ### Variables and rings for polynomials and root searching.
3042
    i=var('i')
3043
    t=var('t')
3044
    inputFunctionVariable = inputFunction.variables()[0]
3045
    function = inputFunction.subs({inputFunctionVariable:i})
3046
    #  Polynomial Rings over the integers, for root finding.
3047
    Zi = ZZ[i]
3048
    Zt = ZZ[t]
3049
    Zit = ZZ[i,t]
3050
    ## Number of iterations limit.
3051
    maxIter = 100000
3052
    #
3053
    ## Set the variable name in Sollya.
3054
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
3055
    ## Compute the scaled function and the degree, in their Sollya version 
3056
    #  once for all.
3057
    (scaledf, sdlb, sdub, silb, siub) = \
3058
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
3059
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
3060
    #print "Scaled bounds:", sdlb, sdub
3061
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
3062
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
3063
    #
3064
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
3065
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
3066
    (unscalingFunction, scalingFunction) = \
3067
        slz_interval_scaling_expression(domainBoundsInterval, i)
3068
    #print scalingFunction, unscalingFunction
3069
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
3070
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
3071
    if internalSollyaPrec < 192:
3072
        internalSollyaPrec = 192
3073
    pobyso_set_prec_sa_so(internalSollyaPrec)
3074
    print "Sollya internal precision:", internalSollyaPrec
3075
    ## Some variables.
3076
    ### General variables
3077
    lb                  = sdlb
3078
    ub                  = sdub
3079
    nbw                 = 0
3080
    intervalUlp         = ub.ulp()
3081
    #### Will be set by slz_interval_and_polynomila_to_sage.
3082
    ic                  = 0 
3083
    icAsInt             = 0    # Set from ic.
3084
    solutionsSet        = set()
3085
    tsErrorWidth        = []
3086
    csErrorVectors      = []
3087
    csVectorsResultants = []
3088
    floatP              = 0  # Taylor polynomial.
3089
    floatPcv            = 0  # Ditto with variable change.
3090
    intvl               = "" # Taylor interval
3091
    terr                = 0  # Taylor error.
3092
    iterCount = 0
3093
    htrnSet = set()
3094
    ### Timers and counters.
3095
    wallTimeStart                   = 0
3096
    cpuTimeStart                    = 0
3097
    taylCondFailedCount             = 0
3098
    coppCondFailedCount             = 0
3099
    resultCondFailedCount           = 0
3100
    coppCondFailed                  = False
3101
    resultCondFailed                = False
3102
    globalResultsList               = []
3103
    basisConstructionsCount         = 0
3104
    basisConstructionsFullTime      = 0
3105
    basisConstructionTime           = 0
3106
    reductionsCount                 = 0
3107
    reductionsFullTime              = 0
3108
    reductionTime                   = 0
3109
    resultantsComputationsCount     = 0
3110
    resultantsComputationsFullTime  = 0
3111
    resultantsComputationTime       = 0
3112
    rootsComputationsCount          = 0
3113
    rootsComputationsFullTime       = 0
3114
    rootsComputationTime            = 0
3115
    print
3116
    ## Global times are started here.
3117
    wallTimeStart                   = walltime()
3118
    cpuTimeStart                    = cputime()
3119
    ## Main loop.
3120
    while True:
3121
        if lb >= sdub:
3122
            print "Lower bound reached upper bound."
3123
            break
3124
        if iterCount == maxIter:
3125
            print "Reached maxIter. Aborting"
3126
            break
3127
        iterCount += 1
3128
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3129
            "log2(numbers)." 
3130
        ### Compute a Sollya polynomial that will honor the Taylor condition.
3131
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
3132
                                                        degreeSo,
3133
                                                        lb,
3134
                                                        ub,
3135
                                                        polyApproxAccur)
3136
        if debug:
3137
            print "Approximation polynomial computed."
3138
        if prceSo is None:
3139
            raise Exception("Could not compute an approximation polynomial.")
3140
        ### Convert back the data into Sage space.                         
3141
        (floatP, floatPcv, intvl, ic, terr) = \
3142
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
3143
                                                 prceSo[1], prceSo[2], 
3144
                                                 prceSo[3]))
3145
        intvl = RRIF(intvl)
3146
        ## Clean-up Sollya stuff.
3147
        for elem in prceSo:
3148
            sollya_lib_clear_obj(elem)
3149
        #print  floatP, floatPcv, intvl, ic, terr
3150
        #print floatP
3151
        #print intvl.endpoints()[0].n(), \
3152
        #      ic.n(),
3153
        #intvl.endpoints()[1].n()
3154
        ### Check returned data.
3155
        #### Is approximation error OK?
3156
        if terr > polyApproxAccur:
3157
            exceptionErrorMess  = \
3158
                "Approximation failed - computed error:" + \
3159
                str(terr) + " - target error: "
3160
            exceptionErrorMess += \
3161
                str(polyApproxAccur) + ". Aborting!"
3162
            raise Exception(exceptionErrorMess)
3163
        #### Is lower bound OK?
3164
        if lb != intvl.endpoints()[0]:
3165
            exceptionErrorMess =  "Wrong lower bound:" + \
3166
                               str(lb) + ". Aborting!"
3167
            raise Exception(exceptionErrorMess)
3168
        #### Set upper bound.
3169
        if ub > intvl.endpoints()[1]:
3170
            ub = intvl.endpoints()[1]
3171
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3172
            "log2(numbers)." 
3173
            taylCondFailedCount += 1
3174
        #### Is interval not degenerate?
3175
        if lb >= ub:
3176
            exceptionErrorMess = "Degenerate interval: " + \
3177
                                "lowerBound(" + str(lb) +\
3178
                                ")>= upperBound(" + str(ub) + \
3179
                                "). Aborting!"
3180
            raise Exception(exceptionErrorMess)
3181
        #### Is interval center ok?
3182
        if ic <= lb or ic >= ub:
3183
            exceptionErrorMess =  "Invalid interval center for " + \
3184
                                str(lb) + ',' + str(ic) + ',' +  \
3185
                                str(ub) + ". Aborting!"
3186
            raise Exception(exceptionErrorMess)
3187
        ##### Current interval width and reset future interval width.
3188
        bw = ub - lb
3189
        nbw = 0
3190
        icAsInt = int(ic * toIntegerFactor)
3191
        #### The following ratio is always >= 1. In case we may want to
3192
        #    enlarge the interval
3193
        curTaylErrRat = polyApproxAccur / terr
3194
        ### Make the  integral transformations.
3195
        #### Bounds and interval center.
3196
        intIc = int(ic * toIntegerFactor)
3197
        intLb = int(lb * toIntegerFactor) - intIc
3198
        intUb = int(ub * toIntegerFactor) - intIc
3199
        #
3200
        #### Polynomials
3201
        basisConstructionTime         = cputime()
3202
        ##### To a polynomial with rational coefficients with rational arguments
3203
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
3204
        ##### To a polynomial with rational coefficients with integer arguments
3205
        ratIntP = \
3206
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
3207
        #####  Ultimately a multivariate polynomial with integer coefficients  
3208
        #      with integer arguments.
3209
        coppersmithTuple = \
3210
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
3211
                                                        precision, 
3212
                                                        targetHardnessToRound, 
3213
                                                        i, t)
3214
        #### Recover Coppersmith information.
3215
        intIntP = coppersmithTuple[0]
3216
        N = coppersmithTuple[1]
3217
        nAtAlpha = N^alpha
3218
        tBound = coppersmithTuple[2]
3219
        leastCommonMultiple = coppersmithTuple[3]
3220
        iBound = max(abs(intLb),abs(intUb))
3221
        basisConstructionsFullTime        += cputime(basisConstructionTime)
3222
        basisConstructionsCount           += 1
3223
        #### Compute the matrix to reduce for debug purpose. Otherwise
3224
        #    slz_compute_coppersmith_reduced_polynomials does the job
3225
        #    invisibly.
3226
        if debug:
3227
            matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
3228
                                                                alpha,
3229
                                                                N,
3230
                                                                iBound,
3231
                                                                tBound)
3232
            maxNorm     = 0
3233
            latticeSize = 0
3234
            matrixFile = file('/tmp/matrixToReduce.txt', 'w')
3235
            for row in matrixToReduce.rows():
3236
                currentNorm = row.norm()
3237
                if currentNorm > maxNorm:
3238
                    maxNorm = currentNorm
3239
                latticeSize += 1
3240
                for elem in row:
3241
                    matrixFile.write(elem.str(base=2) + ",")
3242
                matrixFile.write("\n")
3243
            #matrixFile.write(matrixToReduce.str(radix="2") + "\n")
3244
            matrixFile.close()
3245
            #### We use here binary length as defined in LLL princepts.
3246
            binaryLength = latticeSize * log(maxNorm)
3247
            print "Binary length:", binaryLength.n()
3248
            raise Exception("Deliberate stop here.")
3249
        # End if debug
3250
        reductionTime                     = cputime()
3251
        #### Compute the reduced polynomials.
3252
        print "Starting reduction..."
3253
        ccReducedPolynomialsList =  \
3254
                slz_compute_coppersmith_reduced_polynomials_gram(intIntP, 
3255
                                                                 alpha, 
3256
                                                                 N, 
3257
                                                                 iBound, 
3258
                                                                 tBound)
3259
        print "...reduction accomplished in", cputime(reductionTime), "s."
3260
        if ccReducedPolynomialsList is None:
3261
            raise Exception("Reduction failed.")
3262
        reductionsFullTime    += cputime(reductionTime)
3263
        reductionsCount       += 1
3264
        if len(ccReducedPolynomialsList) < 2:
3265
            print "Nothing to form resultants with."
3266
            print
3267
            coppCondFailedCount += 1
3268
            coppCondFailed = True
3269
            ##### Apply a different shrink factor according to 
3270
            #  the number of compliant polynomials.
3271
            if len(ccReducedPolynomialsList) == 0:
3272
                ub = lb + bw * noCoppersmithIntervalShrink
3273
            else: # At least one compliant polynomial.
3274
                ub = lb + bw * oneCoppersmithIntervalShrink
3275
            if ub > sdub:
3276
                ub = sdub
3277
            if lb == ub:
3278
                raise Exception("Cant shrink interval \
3279
                anymore to get Coppersmith condition.")
3280
            nbw = 0
3281
            continue
3282
        #### We have at least two polynomials.
3283
        #    Let us try to compute resultants.
3284
        #    For each resultant computed, go for the solutions.
3285
        ##### Build the pairs list.
3286
        polyPairsList           = []
3287
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
3288
            for polyInnerIndex in xrange(polyOuterIndex+1, 
3289
                                         len(ccReducedPolynomialsList)):
3290
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
3291
                                      ccReducedPolynomialsList[polyInnerIndex]))
3292
        #### Actual root search.
3293
        iRootsSet           = set()
3294
        hasNonNullResultant = False
3295
        for polyPair in polyPairsList:
3296
            resultantsComputationTime   = cputime()
3297
            currentResultantI = \
3298
                slz_resultant(polyPair[0],
3299
                              polyPair[1],
3300
                              t)
3301
            resultantsComputationsCount    += 1
3302
            resultantsComputationsFullTime +=  \
3303
                cputime(resultantsComputationTime)
3304
            #### Function slz_resultant returns None both for None and O
3305
            #    resultants.
3306
            if currentResultantI is None:
3307
                print "Nul resultant"
3308
                continue # Next polyPair.
3309
            ## We deleted the currentResultantI computation.
3310
            #### We have a non null resultant. From now on, whatever this
3311
            #    root search yields, no extra root search is necessary.
3312
            hasNonNullResultant = True
3313
            #### A constant resultant leads to no root. Root search is done.
3314
            if currentResultantI.degree() < 1:
3315
                print "Resultant is constant:", currentResultantI
3316
                break # There is no root.
3317
            #### Actual iroots computation.
3318
            rootsComputationTime        = cputime()
3319
            iRootsList = Zi(currentResultantI).roots()
3320
            rootsComputationsCount      +=  1
3321
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
3322
            if len(iRootsList) == 0:
3323
                print "No roots in \"i\"."
3324
                break # No roots in i.
3325
            else:
3326
                for iRoot in iRootsList:
3327
                    # A root is given as a (value, multiplicity) tuple.
3328
                    iRootsSet.add(iRoot[0])
3329
        # End loop for polyPair in polyParsList. We only loop again if a 
3330
        # None or zero resultant is found.
3331
        #### Prepare for results for the current interval..
3332
        intervalResultsList = []
3333
        intervalResultsList.append((lb, ub))
3334
        #### Check roots.
3335
        rootsResultsList = []
3336
        for iRoot in iRootsSet:
3337
            specificRootResultsList = []
3338
            failingBounds           = []
3339
            # Root qualifies for modular equation, test it for hardness to round.
3340
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
3341
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
3342
            #print scalingFunction
3343
            scaledHardToRoundCaseAsFloat = \
3344
                scalingFunction(hardToRoundCaseAsFloat) 
3345
            print "Candidate HTRNc at x =", \
3346
                scaledHardToRoundCaseAsFloat.n().str(base=2),
3347
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
3348
                           function,
3349
                           2^-(targetHardnessToRound),
3350
                           RRR):
3351
                print hardToRoundCaseAsFloat, "is HTRN case."
3352
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
3353
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
3354
                    print "Found in interval."
3355
                else:
3356
                    print "Found out of interval."
3357
                # Check the i root is within the i bound.
3358
                if abs(iRoot) > iBound:
3359
                    print "IRoot", iRoot, "is out of bounds for modular equation."
3360
                    print "i bound:", iBound
3361
                    failingBounds.append('i')
3362
                    failingBounds.append(iRoot)
3363
                    failingBounds.append(iBound)
3364
                if len(failingBounds) > 0:
3365
                    specificRootResultsList.append(failingBounds)
3366
            else: # From slz_is_htrn...
3367
                print "is not an HTRN case."
3368
            if len(specificRootResultsList) > 0:
3369
                rootsResultsList.append(specificRootResultsList)
3370
        if len(rootsResultsList) > 0:
3371
            intervalResultsList.append(rootsResultsList)
3372
        ### Check if a non null resultant was found. If not shrink the interval.
3373
        if not hasNonNullResultant:
3374
            print "Only null resultants for this reduction, shrinking interval."
3375
            resultCondFailed      =  True
3376
            resultCondFailedCount += 1
3377
            ### Shrink interval for next iteration.
3378
            ub = lb + bw * onlyNullResultantsShrink
3379
            if ub > sdub:
3380
                ub = sdub
3381
            nbw = 0
3382
            continue
3383
        #### An intervalResultsList has at least the bounds.
3384
        globalResultsList.append(intervalResultsList)   
3385
        #### Compute an incremented width for next upper bound, only
3386
        #    if not Coppersmith condition nor resultant condition
3387
        #    failed at the previous run. 
3388
        if not coppCondFailed and not resultCondFailed:
3389
            nbw = noErrorIntervalStretch * bw
3390
        else:
3391
            nbw = bw
3392
        ##### Reset the failure flags. They will be raised
3393
        #     again if needed.
3394
        coppCondFailed   = False
3395
        resultCondFailed = False
3396
        #### For next iteration (at end of loop)
3397
        #print "nbw:", nbw
3398
        lb  = ub
3399
        ub += nbw     
3400
        if ub > sdub:
3401
            ub = sdub
3402
        print
3403
    # End while True
3404
    ## Main loop just ended.
3405
    globalWallTime = walltime(wallTimeStart)
3406
    globalCpuTime  = cputime(cpuTimeStart)
3407
    ## Output results
3408
    print ; print "Intervals and HTRNs" ; print
3409
    for intervalResultsList in globalResultsList:
3410
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
3411
                               "," + str(intervalResultsList[0][1])  + "]"
3412
        print intervalResultString,
3413
        if len(intervalResultsList) > 1:
3414
            rootsResultsList = intervalResultsList[1]
3415
            specificRootResultIndex = 0
3416
            for specificRootResultsList in rootsResultsList:
3417
                if specificRootResultIndex == 0:
3418
                    print "\t", specificRootResultsList[0],
3419
                else:
3420
                    print " " * len(intervalResultString), "\t", \
3421
                          specificRootResultsList[0],
3422
                if len(specificRootResultsList) > 1:
3423
                    print specificRootResultsList[1]
3424
                specificRootResultIndex += 1
3425
        print ; print
3426
    #print globalResultsList
3427
    #
3428
    print "Timers and counters"
3429
    print
3430
    print "Number of iterations:", iterCount
3431
    print "Taylor condition failures:", taylCondFailedCount
3432
    print "Coppersmith condition failures:", coppCondFailedCount
3433
    print "Resultant condition failures:", resultCondFailedCount
3434
    print "Iterations count: ", iterCount
3435
    print "Number of intervals:", len(globalResultsList)
3436
    print "Number of basis constructions:", basisConstructionsCount 
3437
    print "Total CPU time spent in basis constructions:", \
3438
        basisConstructionsFullTime
3439
    if basisConstructionsCount != 0:
3440
        print "Average basis construction CPU time:", \
3441
            basisConstructionsFullTime/basisConstructionsCount
3442
    print "Number of reductions:", reductionsCount
3443
    print "Total CPU time spent in reductions:", reductionsFullTime
3444
    if reductionsCount != 0:
3445
        print "Average reduction CPU time:", \
3446
            reductionsFullTime/reductionsCount
3447
    print "Number of resultants computation rounds:", \
3448
        resultantsComputationsCount
3449
    print "Total CPU time spent in resultants computation rounds:", \
3450
        resultantsComputationsFullTime
3451
    if resultantsComputationsCount != 0:
3452
        print "Average resultants computation round CPU time:", \
3453
            resultantsComputationsFullTime/resultantsComputationsCount
3454
    print "Number of root finding rounds:", rootsComputationsCount
3455
    print "Total CPU time spent in roots finding rounds:", \
3456
        rootsComputationsFullTime
3457
    if rootsComputationsCount != 0:
3458
        print "Average roots finding round CPU time:", \
3459
            rootsComputationsFullTime/rootsComputationsCount
3460
    print "Global Wall time:", globalWallTime
3461
    print "Global CPU time:", globalCpuTime
3462
    ## Output counters
3463
# End srs_runSLZ-v05_gram
3464
#
3465
def srs_run_SLZ_v05_proj(inputFunction,
3466
                         inputLowerBound,
3467
                         inputUpperBound,
3468
                         alpha,
3469
                         degree,
3470
                         precision,
3471
                         emin,
3472
                         emax,
3473
                         targetHardnessToRound,
3474
                         debug = False):
3475
    """
3476
    changes from plain V5:
3477
       LLL reduction is not performed on the matrix itself but rather on the
3478
       product of the matrix with a uniform random matrix.
3479
       The reduced matrix obtained is discarded but the transformation matrix 
3480
       obtained is used to multiply the original matrix in order to reduced it.
3481
       If a sufficient level of reduction is obtained, we stop here. If not
3482
       the product matrix obtained above is LLL reduced. But as it has been
3483
       pre-reduced at the above step, reduction is supposed to be much fastet.
3484
       In the worst case, both reductions combined should hopefully be faster 
3485
       than a straight single reduction.
3486
    Changes from V4:
3487
        Approximation polynomial has coefficients rounded.
3488
    Changes from V3:
3489
        Root search is changed again:
3490
            - only resultants in i are computed;
3491
            - roots in i are searched for;
3492
            - if any, they are tested for hardness-to-round.
3493
    Changes from V2:
3494
        Root search is changed:
3495
            - we compute the resultants in i and in t;
3496
            - we compute the roots set of each of these resultants;
3497
            - we combine all the possible pairs between the two sets;
3498
            - we check these pairs in polynomials for correctness.
3499
    Changes from V1: 
3500
        1- check for roots as soon as a resultant is computed;
3501
        2- once a non null resultant is found, check for roots;
3502
        3- constant resultant == no root.
3503
    """
3504

    
3505
    if debug:
3506
        print "Function                :", inputFunction
3507
        print "Lower bound             :", inputLowerBound.str(truncate=False)
3508
        print "Upper bounds            :", inputUpperBound.str(truncate=False)
3509
        print "Alpha                   :", alpha
3510
        print "Degree                  :", degree
3511
        print "Precision               :", precision
3512
        print "Emin                    :", emin
3513
        print "Emax                    :", emax
3514
        print "Target hardness-to-round:", targetHardnessToRound
3515
        print
3516
    ## Important constants.
3517
    ### Stretch the interval if no error happens.
3518
    noErrorIntervalStretch = 1 + 2^(-5)
3519
    ### If no vector validates the Coppersmith condition, shrink the interval
3520
    #   by the following factor.
3521
    noCoppersmithIntervalShrink = 1/2
3522
    ### If only (or at least) one vector validates the Coppersmith condition, 
3523
    #   shrink the interval by the following factor.
3524
    oneCoppersmithIntervalShrink = 3/4
3525
    #### If only null resultants are found, shrink the interval by the 
3526
    #    following factor.
3527
    onlyNullResultantsShrink     = 3/4
3528
    ## Structures.
3529
    RRR         = RealField(precision)
3530
    RRIF        = RealIntervalField(precision)
3531
    ## Converting input bound into the "right" field.
3532
    lowerBound = RRR(inputLowerBound)
3533
    upperBound = RRR(inputUpperBound)
3534
    ## Before going any further, check domain and image binade conditions.
3535
    print inputFunction._assume_str(), "at 1:", inputFunction(1).n()
3536
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
3537
    #print "srsv04p:", output, (output is None)
3538
    #
3539
    ## Check if input to thr fix_bounds function is valid.
3540
    if output is None:
3541
        print "Invalid domain/image binades. Domain:",\
3542
        lowerBound.str(truncate=False), upperBound(truncate=False), \
3543
        "Images:", \
3544
        inputFunction(lowerBound), inputFunction(upperBound)
3545
        raise Exception("Invalid domain/image binades.")
3546
    lb = output[0] ; ub = output[1]
3547
    #
3548
    ## Check if bounds have changed.
3549
    if lb != lowerBound or ub != upperBound:
3550
        print "lb:", lb.str(truncate=False), " - ub:", ub.str(truncate=False)
3551
        print "Invalid domain/image binades."
3552
        print "Domain:", lowerBound, upperBound
3553
        print "Images:", \
3554
        inputFunction(lowerBound), inputFunction(upperBound)
3555
        raise Exception("Invalid domain/image binades.")
3556
    #
3557
    ## Progam initialization
3558
    ### Approximation polynomial accuracy and hardness to round.
3559
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
3560
    #polyApproxAccur           = 2^(-(targetHardnessToRound + 12))
3561
    polyTargetHardnessToRound = targetHardnessToRound + 1
3562
    ### Significand to integer conversion ratio.
3563
    toIntegerFactor           = 2^(precision-1)
3564
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
3565
    ### Variables and rings for polynomials and root searching.
3566
    i=var('i')
3567
    t=var('t')
3568
    inputFunctionVariable = inputFunction.variables()[0]
3569
    function = inputFunction.subs({inputFunctionVariable:i})
3570
    #  Polynomial Rings over the integers, for root finding.
3571
    Zi = ZZ[i]
3572
    Zt = ZZ[t]
3573
    Zit = ZZ[i,t]
3574
    ## Number of iterations limit.
3575
    maxIter = 100000
3576
    #
3577
    ## Set the variable name in Sollya.
3578
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
3579
    ## Compute the scaled function and the degree, in their Sollya version 
3580
    #  once for all.
3581
    #print "srsvp initial bounds:",lowerBound, upperBound
3582
    (scaledf, sdlb, sdub, silb, siub) = \
3583
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
3584
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
3585
    #print "srsvp Scaled bounds:", sdlb, sdub
3586
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
3587
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
3588
    #
3589
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
3590
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
3591
    (unscalingFunction, scalingFunction) = \
3592
        slz_interval_scaling_expression(domainBoundsInterval, i)
3593
    #print scalingFunction, unscalingFunction
3594
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
3595
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
3596
    if internalSollyaPrec < 192:
3597
        internalSollyaPrec = 192
3598
    pobyso_set_prec_sa_so(internalSollyaPrec)
3599
    print "Sollya internal precision:", internalSollyaPrec
3600
    ## Some variables.
3601
    ### General variables
3602
    lb                  = sdlb
3603
    ub                  = sdub
3604
    nbw                 = 0
3605
    intervalUlp         = ub.ulp()
3606
    #### Will be set by slz_interval_and_polynomila_to_sage.
3607
    ic                  = 0 
3608
    icAsInt             = 0    # Set from ic.
3609
    solutionsSet        = set()
3610
    tsErrorWidth        = []
3611
    csErrorVectors      = []
3612
    csVectorsResultants = []
3613
    floatP              = 0  # Taylor polynomial.
3614
    floatPcv            = 0  # Ditto with variable change.
3615
    intvl               = "" # Taylor interval
3616
    terr                = 0  # Taylor error.
3617
    iterCount = 0
3618
    htrnSet = set()
3619
    ### Timers and counters.
3620
    wallTimeStart                   = 0
3621
    cpuTimeStart                    = 0
3622
    taylCondFailedCount             = 0
3623
    coppCondFailedCount             = 0
3624
    resultCondFailedCount           = 0
3625
    coppCondFailed                  = False
3626
    resultCondFailed                = False
3627
    globalResultsList               = []
3628
    basisConstructionsCount         = 0
3629
    basisConstructionsFullTime      = 0
3630
    basisConstructionTime           = 0
3631
    reductionsCount                 = 0
3632
    reductionsFullTime              = 0
3633
    reductionTime                   = 0
3634
    resultantsComputationsCount     = 0
3635
    resultantsComputationsFullTime  = 0
3636
    resultantsComputationTime       = 0
3637
    rootsComputationsCount          = 0
3638
    rootsComputationsFullTime       = 0
3639
    rootsComputationTime            = 0
3640
    print
3641
    ## Global times are started here.
3642
    wallTimeStart                   = walltime()
3643
    cpuTimeStart                    = cputime()
3644
    ## Main loop.
3645
    while True:
3646
        if lb >= sdub:
3647
            print "Lower bound reached upper bound."
3648
            break
3649
        if iterCount == maxIter:
3650
            print "Reached maxIter. Aborting"
3651
            break
3652
        iterCount += 1
3653
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3654
            "log2(numbers)." 
3655
        ### Compute a Sollya polynomial that will honor the Taylor condition.
3656
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
3657
                                                        degreeSo,
3658
                                                        lb,
3659
                                                        ub,
3660
                                                        polyApproxAccur)
3661
        if debug:
3662
            print "Approximation polynomial computed."
3663
        if prceSo is None:
3664
            raise Exception("Could not compute an approximation polynomial.")
3665
        ### Convert back the data into Sage space.                         
3666
        (floatP, floatPcv, intvl, ic, terr) = \
3667
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
3668
                                                 prceSo[1], prceSo[2], 
3669
                                                 prceSo[3]))
3670
        intvl = RRIF(intvl)
3671
        ## Clean-up Sollya stuff.
3672
        for elem in prceSo:
3673
            sollya_lib_clear_obj(elem)
3674
        #print  floatP, floatPcv, intvl, ic, terr
3675
        #print floatP
3676
        #print intvl.endpoints()[0].n(), \
3677
        #      ic.n(),
3678
        #intvl.endpoints()[1].n()
3679
        ### Check returned data.
3680
        #### Is approximation error OK?
3681
        if terr > polyApproxAccur:
3682
            exceptionErrorMess  = \
3683
                "Approximation failed - computed error:" + \
3684
                str(terr) + " - target error: "
3685
            exceptionErrorMess += \
3686
                str(polyApproxAccur) + ". Aborting!"
3687
            raise Exception(exceptionErrorMess)
3688
        #### Is lower bound OK?
3689
        if lb != intvl.endpoints()[0]:
3690
            exceptionErrorMess =  "Wrong lower bound:" + \
3691
                               str(lb) + ". Aborting!"
3692
            raise Exception(exceptionErrorMess)
3693
        #### Set upper bound.
3694
        if ub > intvl.endpoints()[1]:
3695
            ub = intvl.endpoints()[1]
3696
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
3697
            "log2(numbers)." 
3698
            taylCondFailedCount += 1
3699
        #### Is interval not degenerate?
3700
        if lb >= ub:
3701
            exceptionErrorMess = "Degenerate interval: " + \
3702
                                "lowerBound(" + str(lb) +\
3703
                                ")>= upperBound(" + str(ub) + \
3704
                                "). Aborting!"
3705
            raise Exception(exceptionErrorMess)
3706
        #### Is interval center ok?
3707
        if ic <= lb or ic >= ub:
3708
            exceptionErrorMess =  "Invalid interval center for " + \
3709
                                str(lb) + ',' + str(ic) + ',' +  \
3710
                                str(ub) + ". Aborting!"
3711
            raise Exception(exceptionErrorMess)
3712
        ##### Current interval width and reset future interval width.
3713
        bw = ub - lb
3714
        nbw = 0
3715
        icAsInt = int(ic * toIntegerFactor)
3716
        #### The following ratio is always >= 1. In case we may want to
3717
        #    enlarge the interval
3718
        curTaylErrRat = polyApproxAccur / terr
3719
        ### Make the  integral transformations.
3720
        #### Bounds and interval center.
3721
        intIc = int(ic * toIntegerFactor)
3722
        intLb = int(lb * toIntegerFactor) - intIc
3723
        intUb = int(ub * toIntegerFactor) - intIc
3724
        #
3725
        #### Polynomials
3726
        basisConstructionTime         = cputime()
3727
        ##### To a polynomial with rational coefficients with rational arguments
3728
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
3729
        ##### To a polynomial with rational coefficients with integer arguments
3730
        ratIntP = \
3731
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
3732
        #####  Ultimately a multivariate polynomial with integer coefficients  
3733
        #      with integer arguments.
3734
        coppersmithTuple = \
3735
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
3736
                                                        precision, 
3737
                                                        targetHardnessToRound, 
3738
                                                        i, t)
3739
        #### Recover Coppersmith information.
3740
        intIntP = coppersmithTuple[0]
3741
        N = coppersmithTuple[1]
3742
        nAtAlpha = N^alpha
3743
        tBound = coppersmithTuple[2]
3744
        leastCommonMultiple = coppersmithTuple[3]
3745
        iBound = max(abs(intLb),abs(intUb))
3746
        basisConstructionsFullTime        += cputime(basisConstructionTime)
3747
        basisConstructionsCount           += 1
3748
        #### Compute the matrix to reduce for debug purpose. Otherwise
3749
        #    slz_compute_coppersmith_reduced_polynomials does the job
3750
        #    invisibly.
3751
        if debug:
3752
            matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
3753
                                                                alpha,
3754
                                                                N,
3755
                                                                iBound,
3756
                                                                tBound)
3757
            maxNorm     = 0
3758
            latticeSize = 0
3759
            matrixFile = file('/tmp/matrixToReduce.txt', 'w')
3760
            for row in matrixToReduce.rows():
3761
                currentNorm = row.norm()
3762
                if currentNorm > maxNorm:
3763
                    maxNorm = currentNorm
3764
                latticeSize += 1
3765
                for elem in row:
3766
                    matrixFile.write(elem.str(base=2) + ",")
3767
                matrixFile.write("\n")
3768
            #matrixFile.write(matrixToReduce.str(radix="2") + "\n")
3769
            matrixFile.close()
3770
            #### We use here binary length as defined in LLL princepts.
3771
            binaryLength = latticeSize * log(maxNorm)
3772
            print "Binary length:", binaryLength.n()
3773
            #raise Exception("Deliberate stop here.")
3774
        # End if debug
3775
        reductionTime                     = cputime()
3776
        #### Compute the reduced polynomials.
3777
        print "Starting reduction..."
3778
        ccReducedPolynomialsList =  \
3779
                slz_compute_coppersmith_reduced_polynomials_proj(intIntP, 
3780
                                                                 alpha, 
3781
                                                                 N, 
3782
                                                                 iBound, 
3783
                                                                 tBound)
3784
        print "...reduction accomplished in", cputime(reductionTime), "s."
3785
        if ccReducedPolynomialsList is None:
3786
            raise Exception("Reduction failed.")
3787
        reductionsFullTime    += cputime(reductionTime)
3788
        reductionsCount       += 1
3789
        if len(ccReducedPolynomialsList) < 2:
3790
            print "Nothing to form resultants with."
3791
            print
3792
            coppCondFailedCount += 1
3793
            coppCondFailed = True
3794
            ##### Apply a different shrink factor according to 
3795
            #  the number of compliant polynomials.
3796
            if len(ccReducedPolynomialsList) == 0:
3797
                ub = lb + bw * noCoppersmithIntervalShrink
3798
            else: # At least one compliant polynomial.
3799
                ub = lb + bw * oneCoppersmithIntervalShrink
3800
            if ub > sdub:
3801
                ub = sdub
3802
            if lb == ub:
3803
                raise Exception("Cant shrink interval \
3804
                anymore to get Coppersmith condition.")
3805
            nbw = 0
3806
            continue
3807
        #### We have at least two polynomials.
3808
        #    Let us try to compute resultants.
3809
        #    For each resultant computed, go for the solutions.
3810
        ##### Build the pairs list.
3811
        polyPairsList           = []
3812
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
3813
            for polyInnerIndex in xrange(polyOuterIndex+1, 
3814
                                         len(ccReducedPolynomialsList)):
3815
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
3816
                                      ccReducedPolynomialsList[polyInnerIndex]))
3817
        #### Actual root search.
3818
        iRootsSet           = set()
3819
        hasNonNullResultant = False
3820
        for polyPair in polyPairsList:
3821
            resultantsComputationTime = cputime()
3822
            currentResultantI = \
3823
                slz_resultant(polyPair[0],
3824
                              polyPair[1],
3825
                              t)
3826
            resultantsComputationsCount    += 1
3827
            resultantsComputationsFullTime +=  \
3828
                cputime(resultantsComputationTime)
3829
            #### Function slz_resultant returns None both for None and O
3830
            #    resultants.
3831
            if currentResultantI is None:
3832
                print "Nul resultant"
3833
                continue # Next polyPair.
3834
            ## We deleted the currentResultantI computation.
3835
            #### We have a non null resultant. From now on, whatever this
3836
            #    root search yields, no extra root search is necessary.
3837
            hasNonNullResultant = True
3838
            #### A constant resultant leads to no root. Root search is done.
3839
            if currentResultantI.degree() < 1:
3840
                print "Resultant is constant:", currentResultantI
3841
                break # There is no root.
3842
            #### Actual iroots computation.
3843
            rootsComputationTime        = cputime()
3844
            iRootsList = Zi(currentResultantI).roots()
3845
            rootsComputationsCount      +=  1
3846
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
3847
            if len(iRootsList) == 0:
3848
                print "No roots in \"i\"."
3849
                #break # No roots in i.
3850
            else:
3851
                for iRoot in iRootsList:
3852
                    # A root is given as a (value, multiplicity) tuple.
3853
                    iRootsSet.add(iRoot[0])
3854
                    print "Root added."
3855
            #### A non null, non constant resultant has been tested
3856
            #    for. There is no need to check for another one. Break
3857
            #    whether roots are found or not.
3858
            break
3859
        # End loop for polyPair in polyParsList. We only loop again if a 
3860
        # None or zero resultant is found.
3861
        #### Prepare for results for the current interval..
3862
        intervalResultsList = []
3863
        intervalResultsList.append((lb, ub))
3864
        #### Check roots.
3865
        rootsResultsList = []
3866
        for iRoot in iRootsSet:
3867
            specificRootResultsList = []
3868
            failingBounds           = []
3869
            # Root qualifies for modular equation, test it for hardness to round.
3870
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
3871
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
3872
            #print scalingFunction
3873
            scaledHardToRoundCaseAsFloat = \
3874
                scalingFunction(hardToRoundCaseAsFloat) 
3875
            print "Candidate HTRNc at x =", \
3876
                scaledHardToRoundCaseAsFloat.n().str(base=2),
3877
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
3878
                           function,
3879
                           2^-(targetHardnessToRound),
3880
                           RRR):
3881
                print hardToRoundCaseAsFloat, "is HTRN case."
3882
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
3883
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
3884
                    print "Found in interval."
3885
                else:
3886
                    print "Found out of interval."
3887
                # Check the i root is within the i bound.
3888
                if abs(iRoot) > iBound:
3889
                    print "IRoot", iRoot, "is out of bounds for modular equation."
3890
                    print "i bound:", iBound
3891
                    failingBounds.append('i')
3892
                    failingBounds.append(iRoot)
3893
                    failingBounds.append(iBound)
3894
                if len(failingBounds) > 0:
3895
                    specificRootResultsList.append(failingBounds)
3896
            else: # From slz_is_htrn...
3897
                print "is not an HTRN case."
3898
            if len(specificRootResultsList) > 0:
3899
                rootsResultsList.append(specificRootResultsList)
3900
        if len(rootsResultsList) > 0:
3901
            intervalResultsList.append(rootsResultsList)
3902
        ### Check if a non null resultant was found. If not shrink the interval.
3903
        if not hasNonNullResultant:
3904
            print "Only null resultants for this reduction, shrinking interval."
3905
            resultCondFailed      =  True
3906
            resultCondFailedCount += 1
3907
            ### Shrink interval for next iteration.
3908
            ub = lb + bw * onlyNullResultantsShrink
3909
            if ub > sdub:
3910
                ub = sdub
3911
            nbw = 0
3912
            continue
3913
        #### An intervalResultsList has at least the bounds.
3914
        globalResultsList.append(intervalResultsList)   
3915
        #### Compute an incremented width for next upper bound, only
3916
        #    if not Coppersmith condition nor resultant condition
3917
        #    failed at the previous run. 
3918
        if not coppCondFailed and not resultCondFailed:
3919
            nbw = noErrorIntervalStretch * bw
3920
        else:
3921
            nbw = bw
3922
        ##### Reset the failure flags. They will be raised
3923
        #     again if needed.
3924
        coppCondFailed   = False
3925
        resultCondFailed = False
3926
        #### For next iteration (at end of loop)
3927
        #print "nbw:", nbw
3928
        lb  = ub
3929
        ub += nbw     
3930
        if ub > sdub:
3931
            ub = sdub
3932
        print
3933
    # End while True
3934
    ## Main loop just ended.
3935
    globalWallTime = walltime(wallTimeStart)
3936
    globalCpuTime  = cputime(cpuTimeStart)
3937
    ## Output results
3938
    print ; print "Intervals and HTRNs" ; print
3939
    for intervalResultsList in globalResultsList:
3940
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
3941
                               "," + str(intervalResultsList[0][1])  + "]"
3942
        print intervalResultString,
3943
        if len(intervalResultsList) > 1:
3944
            rootsResultsList = intervalResultsList[1]
3945
            specificRootResultIndex = 0
3946
            for specificRootResultsList in rootsResultsList:
3947
                if specificRootResultIndex == 0:
3948
                    print "\t", specificRootResultsList[0],
3949
                else:
3950
                    print " " * len(intervalResultString), "\t", \
3951
                          specificRootResultsList[0],
3952
                if len(specificRootResultsList) > 1:
3953
                    print specificRootResultsList[1]
3954
                specificRootResultIndex += 1
3955
        print ; print
3956
    #print globalResultsList
3957
    #
3958
    print "Timers and counters"
3959
    print
3960
    print "Number of iterations:", iterCount
3961
    print "Taylor condition failures:", taylCondFailedCount
3962
    print "Coppersmith condition failures:", coppCondFailedCount
3963
    print "Resultant condition failures:", resultCondFailedCount
3964
    print "Iterations count: ", iterCount
3965
    print "Number of intervals:", len(globalResultsList)
3966
    print "Number of basis constructions:", basisConstructionsCount 
3967
    print "Total CPU time spent in basis constructions:", \
3968
        basisConstructionsFullTime
3969
    if basisConstructionsCount != 0:
3970
        print "Average basis construction CPU time:", \
3971
            basisConstructionsFullTime/basisConstructionsCount
3972
    print "Number of reductions:", reductionsCount
3973
    print "Total CPU time spent in reductions:", reductionsFullTime
3974
    if reductionsCount != 0:
3975
        print "Average reduction CPU time:", \
3976
            reductionsFullTime/reductionsCount
3977
    print "Number of resultants computation rounds:", \
3978
        resultantsComputationsCount
3979
    print "Total CPU time spent in resultants computation rounds:", \
3980
        resultantsComputationsFullTime
3981
    if resultantsComputationsCount != 0:
3982
        print "Average resultants computation round CPU time:", \
3983
            resultantsComputationsFullTime/resultantsComputationsCount
3984
    print "Number of root finding rounds:", rootsComputationsCount
3985
    print "Total CPU time spent in roots finding rounds:", \
3986
        rootsComputationsFullTime
3987
    if rootsComputationsCount != 0:
3988
        print "Average roots finding round CPU time:", \
3989
            rootsComputationsFullTime/rootsComputationsCount
3990
    print "Global Wall time:", globalWallTime
3991
    print "Global CPU time:", globalCpuTime
3992
    ## Output counters
3993
# End srs_runSLZ-v05_proj
3994
#
3995
def srs_run_SLZ_v06(inputFunction,
3996
                    inputLowerBound,
3997
                    inputUpperBound,
3998
                    alpha,
3999
                    degree,
4000
                    precision,
4001
                    emin,
4002
                    emax,
4003
                    targetHardnessToRound,
4004
                    debug = True):
4005
    """
4006
    Changes from V5:
4007
        Very verbose
4008
    Changes from V4:
4009
        Approximation polynomial has coefficients rounded.
4010
    Changes from V3:
4011
        Root search is changed again:
4012
            - only resultants in i are computed;
4013
            - roots in i are searched for;
4014
            - if any, they are tested for hardness-to-round.
4015
    Changes from V2:
4016
        Root search is changed:
4017
            - we compute the resultants in i and in t;
4018
            - we compute the roots set of each of these resultants;
4019
            - we combine all the possible pairs between the two sets;
4020
            - we check these pairs in polynomials for correctness.
4021
    Changes from V1: 
4022
        1- check for roots as soon as a resultant is computed;
4023
        2- once a non null resultant is found, check for roots;
4024
        3- constant resultant == no root.
4025
    """
4026
    if debug:
4027
        print "Function                :", inputFunction
4028
        print "Lower bound             :", inputLowerBound
4029
        print "Upper bounds            :", inputUpperBound
4030
        print "Alpha                   :", alpha
4031
        print "Degree                  :", degree
4032
        print "Precision               :", precision
4033
        print "Emin                    :", emin
4034
        print "Emax                    :", emax
4035
        print "Target hardness-to-round:", targetHardnessToRound
4036
        print
4037
    ## Important constants.
4038
    ### Stretch the interval if no error happens.
4039
    noErrorIntervalStretch = 1 + 2^(-5)
4040
    ### If no vector validates the Coppersmith condition, shrink the interval
4041
    #   by the following factor.
4042
    noCoppersmithIntervalShrink = 1/2
4043
    ### If only (or at least) one vector validates the Coppersmith condition, 
4044
    #   shrink the interval by the following factor.
4045
    oneCoppersmithIntervalShrink = 3/4
4046
    #### If only null resultants are found, shrink the interval by the 
4047
    #    following factor.
4048
    onlyNullResultantsShrink     = 3/4
4049
    ## Structures.
4050
    RRR         = RealField(precision)
4051
    RRIF        = RealIntervalField(precision)
4052
    ## Converting input bound into the "right" field.
4053
    lowerBound = RRR(inputLowerBound)
4054
    upperBound = RRR(inputUpperBound)
4055
    ## Before going any further, check domain and image binade conditions.
4056
    print inputFunction(1).n()
4057
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
4058
    if output is None:
4059
        print "Invalid domain/image binades. Domain:",\
4060
        lowerBound, upperBound, "Images:", \
4061
        inputFunction(lowerBound), inputFunction(upperBound)
4062
        raise Exception("Invalid domain/image binades.")
4063
    lb = output[0] ; ub = output[1]
4064
    if lb != lowerBound or ub != upperBound:
4065
        print "lb:", lb, " - ub:", ub
4066
        print "Invalid domain/image binades. Domain:",\
4067
        lowerBound, upperBound, "Images:", \
4068
        inputFunction(lowerBound), inputFunction(upperBound)
4069
        raise Exception("Invalid domain/image binades.")
4070
    #
4071
    ## Progam initialization
4072
    ### Approximation polynomial accuracy and hardness to round.
4073
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
4074
    polyTargetHardnessToRound = targetHardnessToRound + 1
4075
    ### Significand to integer conversion ratio.
4076
    toIntegerFactor           = 2^(precision-1)
4077
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
4078
    ### Variables and rings for polynomials and root searching.
4079
    i=var('i')
4080
    t=var('t')
4081
    inputFunctionVariable = inputFunction.variables()[0]
4082
    function = inputFunction.subs({inputFunctionVariable:i})
4083
    #  Polynomial Rings over the integers, for root finding.
4084
    Zi = ZZ[i]
4085
    ## Number of iterations limit.
4086
    maxIter = 100000
4087
    #
4088
    ## Set the variable name in Sollya.
4089
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
4090
    ## Compute the scaled function and the degree, in their Sollya version 
4091
    #  once for all.
4092
    (scaledf, sdlb, sdub, silb, siub) = \
4093
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
4094
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
4095
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
4096
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
4097
    #
4098
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
4099
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
4100
    (unscalingFunction, scalingFunction) = \
4101
        slz_interval_scaling_expression(domainBoundsInterval, i)
4102
    #print scalingFunction, unscalingFunction
4103
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
4104
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
4105
    if internalSollyaPrec < 192:
4106
        internalSollyaPrec = 192
4107
    pobyso_lib_init()
4108
    pobyso_set_prec_sa_so(internalSollyaPrec)
4109
    print "Sollya internal precision:", internalSollyaPrec
4110
    targetPlusOnePrecRF       = RealField(RRR.prec()+1)
4111
    if internalSollyaPrec < 1024:
4112
        quasiExactRF              = RealField(1014)
4113
    else:
4114
        quasiExactRF              = RealField(internalSollyaPrec) 
4115
    ## Some variables.
4116
    ### General variables
4117
    lb                  = sdlb
4118
    ub                  = sdub
4119
    nbw                 = 0
4120
    intervalUlp         = ub.ulp()
4121
    #### Will be set by slz_interval_and_polynomila_to_sage.
4122
    ic                  = 0 
4123
    icAsInt             = 0    # Set from ic.
4124
    solutionsSet        = set()
4125
    tsErrorWidth        = []
4126
    csErrorVectors      = []
4127
    csVectorsResultants = []
4128
    floatP              = 0  # Taylor polynomial.
4129
    floatPcv            = 0  # Ditto with variable change.
4130
    intvl               = "" # Taylor interval
4131
    terr                = 0  # Taylor error.
4132
    iterCount = 0
4133
    htrnSet = set()
4134
    ### Timers and counters.
4135
    wallTimeStart                   = 0
4136
    cpuTimeStart                    = 0
4137
    taylCondFailedCount             = 0
4138
    coppCondFailedCount             = 0
4139
    resultCondFailedCount           = 0
4140
    coppCondFailed                  = False
4141
    resultCondFailed                = False
4142
    globalResultsList               = []
4143
    basisConstructionsCount         = 0
4144
    basisConstructionsFullTime      = 0
4145
    basisConstructionTime           = 0
4146
    reductionsCount                 = 0
4147
    reductionsFullTime              = 0
4148
    reductionTime                   = 0
4149
    resultantsComputationsCount     = 0
4150
    resultantsComputationsFullTime  = 0
4151
    resultantsComputationTime       = 0
4152
    rootsComputationsCount          = 0
4153
    rootsComputationsFullTime       = 0
4154
    rootsComputationTime            = 0
4155
    print
4156
    ## Global times are started here.
4157
    wallTimeStart                   = walltime()
4158
    cpuTimeStart                    = cputime()
4159
    ## Main loop.
4160
    while True:
4161
        if lb >= sdub:
4162
            print "Lower bound reached upper bound."
4163
            break
4164
        if iterCount == maxIter:
4165
            print "Reached maxIter. Aborting"
4166
            break
4167
        iterCount += 1
4168
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4169
            "log2(numbers)." 
4170
        #print "Debugging..."
4171
        ### Compute a Sollya polynomial that will honor the Taylor condition.
4172
        prceSo = slz_compute_polynomial_and_interval_02(scaledfSo,
4173
                                                        degreeSo,
4174
                                                        lb,
4175
                                                        ub,
4176
                                                        polyApproxAccur,
4177
                                                        debug=True)
4178
        if debug:
4179
            print "Sollya Taylor polynomial:", ; pobyso_autoprint(prceSo[0])
4180
            print "Sollya interval         :", ; pobyso_autoprint(prceSo[1])
4181
            print "Sollya interval center  :", ; pobyso_autoprint(prceSo[2])
4182
            print "Sollya Taylor error     :", ; pobyso_autoprint(prceSo[3])
4183

    
4184
        ### Convert back the data into Sage space.                         
4185
        (floatP, floatPcv, intvl, ic, terr) = \
4186
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
4187
                                                 prceSo[1], prceSo[2], 
4188
                                                 prceSo[3]))
4189
        print "Sage Taylor polynomial:", floatP, floatP.parent()
4190
        floatPcoeffs = floatP.coefficients()
4191
        for coeff in floatPcoeffs:
4192
            print coeff.n(prec=coeff.parent().prec()).str(base=2)
4193
            print coeff.n(prec=coeff.parent().prec())
4194
        intvl = RRIF(intvl)
4195
        ## Clean-up Sollya stuff.
4196
        for elem in prceSo:
4197
            sollya_lib_clear_obj(elem)
4198
        #print  floatP, floatPcv, intvl, ic, terr
4199
        #print floatP
4200
        #print intvl.endpoints()[0].n(), \
4201
        #      ic.n(),
4202
        #intvl.endpoints()[1].n()
4203
        ### Check returned data.
4204
        #### Is approximation error OK?
4205
        if terr > polyApproxAccur:
4206
            exceptionErrorMess  = \
4207
                "Approximation failed - computed error:" + \
4208
                str(terr) + " - target error: "
4209
            exceptionErrorMess += \
4210
                str(polyApproxAccur) + ". Aborting!"
4211
            raise Exception(exceptionErrorMess)
4212
        #### Is lower bound OK?
4213
        if lb != intvl.endpoints()[0]:
4214
            exceptionErrorMess =  "Wrong lower bound:" + \
4215
                               str(lb) + ". Aborting!"
4216
            raise Exception(exceptionErrorMess)
4217
        #### Set upper bound.
4218
        if ub > intvl.endpoints()[1]:
4219
            ub = intvl.endpoints()[1]
4220
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4221
            "log2(numbers)." 
4222
            taylCondFailedCount += 1
4223
        #### Is interval not degenerate?
4224
        if lb >= ub:
4225
            exceptionErrorMess = "Degenerate interval: " + \
4226
                                "lowerBound(" + str(lb) +\
4227
                                ")>= upperBound(" + str(ub) + \
4228
                                "). Aborting!"
4229
            raise Exception(exceptionErrorMess)
4230
        #### Is interval center ok?
4231
        if ic <= lb or ic >= ub:
4232
            exceptionErrorMess =  "Invalid interval center for " + \
4233
                                str(lb) + ',' + str(ic) + ',' +  \
4234
                                str(ub) + ". Aborting!"
4235
            raise Exception(exceptionErrorMess)
4236
        ##### Current interval width and reset future interval width.
4237
        bw = ub - lb
4238
        nbw = 0
4239
        icAsInt = int(ic * toIntegerFactor)
4240
        #### The following ratio is always >= 1. In case we may want to
4241
        #    enlarge the interval
4242
        curTaylErrRat = polyApproxAccur / terr
4243
        ### Make the  integral transformations.
4244
        #### Bounds and interval center.
4245
        intIc = int(ic * toIntegerFactor)
4246
        intLb = int(lb * toIntegerFactor) - intIc
4247
        intUb = int(ub * toIntegerFactor) - intIc
4248
        #
4249
        #### Polynomials
4250
        basisConstructionTime         = cputime()
4251
        ##### To a polynomial with rational coefficients with rational arguments
4252
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
4253
        if debug:
4254
            print "Polynomial: rational coefficients for rational argument:"
4255
            print ratRatP
4256
        ##### To a polynomial with rational coefficients with integer arguments
4257
        ratIntP = \
4258
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
4259
        if debug:
4260
            print "Polynomial: rational coefficients for integer argument:"
4261
            print ratIntP
4262
        #####  Ultimately a multivariate polynomial with integer coefficients  
4263
        #      with integer arguments.
4264
        coppersmithTuple = \
4265
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
4266
                                                        precision, 
4267
                                                        targetHardnessToRound, 
4268
                                                        i, t)
4269
        #### Recover Coppersmith information.
4270
        intIntP = coppersmithTuple[0]
4271
        N = coppersmithTuple[1]
4272
        nAtAlpha = N^alpha
4273
        tBound = coppersmithTuple[2]
4274
        leastCommonMultiple = coppersmithTuple[3]
4275
        iBound = max(abs(intLb),abs(intUb))
4276
        if debug:
4277
            print "Polynomial: integer coefficients for integer argument:"
4278
            print intIntP
4279
            print "N:", N
4280
            print "t bound:", tBound
4281
            print "i bound:", iBound
4282
            print "Least common multiple:", leastCommonMultiple
4283
        basisConstructionsFullTime        += cputime(basisConstructionTime)
4284
        basisConstructionsCount           += 1
4285
        
4286
        #### Compute the matrix to reduce.
4287
        matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
4288
                                                            alpha,
4289
                                                            N,
4290
                                                            iBound,
4291
                                                            tBound,
4292
                                                            True)
4293
        matrixFile = file('/tmp/matrixToReduce.txt', 'w')
4294
        for row in matrixToReduce.rows():
4295
            matrixFile.write(str(row) + "\n")
4296
        matrixFile.close()
4297
        #raise Exception("Deliberate stop here.")
4298
        
4299
        reductionTime                     = cputime()
4300
        #### Compute the reduced polynomials.
4301
        ccReducedPolynomialsList =  \
4302
                slz_compute_coppersmith_reduced_polynomials_with_lattice_volume(intIntP, 
4303
                                                            alpha, 
4304
                                                            N, 
4305
                                                            iBound, 
4306
                                                            tBound,
4307
                                                            True)
4308
        if ccReducedPolynomialsList is None:
4309
            raise Exception("Reduction failed.")
4310
        reductionsFullTime    += cputime(reductionTime)
4311
        reductionsCount       += 1
4312
        if len(ccReducedPolynomialsList) < 2:
4313
            print "Nothing to form resultants with."
4314
            print
4315
            coppCondFailedCount += 1
4316
            coppCondFailed = True
4317
            ##### Apply a different shrink factor according to 
4318
            #  the number of compliant polynomials.
4319
            if len(ccReducedPolynomialsList) == 0:
4320
                ub = lb + bw * noCoppersmithIntervalShrink
4321
            else: # At least one compliant polynomial.
4322
                ub = lb + bw * oneCoppersmithIntervalShrink
4323
            if ub > sdub:
4324
                ub = sdub
4325
            if lb == ub:
4326
                raise Exception("Cant shrink interval \
4327
                anymore to get Coppersmith condition.")
4328
            nbw = 0
4329
            continue
4330
        #### We have at least two polynomials.
4331
        #    Let us try to compute resultants.
4332
        #    For each resultant computed, go for the solutions.
4333
        ##### Build the pairs list.
4334
        polyPairsList           = []
4335
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
4336
            for polyInnerIndex in xrange(polyOuterIndex+1, 
4337
                                         len(ccReducedPolynomialsList)):
4338
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
4339
                                      ccReducedPolynomialsList[polyInnerIndex]))
4340
        #### Actual root search.
4341
        iRootsSet           = set()
4342
        hasNonNullResultant = False
4343
        for polyPair in polyPairsList:
4344
            resultantsComputationTime   = cputime()
4345
            currentResultantI = \
4346
                slz_resultant(polyPair[0],
4347
                              polyPair[1],
4348
                              t,
4349
                              debug=True)
4350
            resultantsComputationsCount    += 1
4351
            resultantsComputationsFullTime +=  \
4352
                cputime(resultantsComputationTime)
4353
            #### Function slz_resultant returns None both for None and O
4354
            #    resultants.
4355
            if currentResultantI is None:
4356
                print "Nul resultant"
4357
                continue # Next polyPair.
4358
            ## We deleted the currentResultantI computation.
4359
            #### We have a non null resultant. From now on, whatever this
4360
            #    root search yields, no extra root search is necessary.
4361
            hasNonNullResultant = True
4362
            #### A constant resultant leads to no root. Root search is done.
4363
            if currentResultantI.degree() < 1:
4364
                print "Resultant is constant:", currentResultantI
4365
                break # There is no root.
4366
            #### Actual iroots computation.
4367
            rootsComputationTime        = cputime()
4368
            iRootsList = Zi(currentResultantI).roots()
4369
            rootsComputationsCount      +=  1
4370
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
4371
            if len(iRootsList) == 0:
4372
                print "No roots in \"i\"."
4373
                break # No roots in i.
4374
            else:
4375
                for iRoot in iRootsList:
4376
                    # A root is given as a (value, multiplicity) tuple.
4377
                    iRootsSet.add(iRoot[0])
4378
        # End loop for polyPair in polyParsList. We only loop again if a 
4379
        # None or zero resultant is found.
4380
        #### Prepare for results for the current interval..
4381
        intervalResultsList = []
4382
        intervalResultsList.append((lb, ub))
4383
        #### Check roots.
4384
        rootsResultsList = []
4385
        for iRoot in iRootsSet:
4386
            specificRootResultsList = []
4387
            failingBounds           = []
4388
            # Root qualifies for modular equation, test it for hardness to round.
4389
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
4390
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
4391
            #print scalingFunction
4392
            scaledHardToRoundCaseAsFloat = \
4393
                scalingFunction(hardToRoundCaseAsFloat) 
4394
            print "Candidate HTRNc at x =", \
4395
                scaledHardToRoundCaseAsFloat.n().str(base=2),
4396
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
4397
                           function,
4398
                           2^-(targetHardnessToRound),
4399
                           RRR,
4400
                           targetPlusOnePrecRF,
4401
                           quasiExactRF):
4402
                print hardToRoundCaseAsFloat, "is HTRN case."
4403
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
4404
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
4405
                    print "Found in interval."
4406
                else:
4407
                    print "Found out of interval."
4408
                # Check the i root is within the i bound.
4409
                if abs(iRoot) > iBound:
4410
                    print "IRoot", iRoot, "is out of bounds for modular equation."
4411
                    print "i bound:", iBound
4412
                    failingBounds.append('i')
4413
                    failingBounds.append(iRoot)
4414
                    failingBounds.append(iBound)
4415
                if len(failingBounds) > 0:
4416
                    specificRootResultsList.append(failingBounds)
4417
            else: # From slz_is_htrn...
4418
                print "is not an HTRN case for integer value:", iRoot
4419
            if len(specificRootResultsList) > 0:
4420
                rootsResultsList.append(specificRootResultsList)
4421
        if len(rootsResultsList) > 0:
4422
            intervalResultsList.append(rootsResultsList)
4423
        ### Check if a non null resultant was found. If not shrink the interval.
4424
        if not hasNonNullResultant:
4425
            print "Only null resultants for this reduction, shrinking interval."
4426
            resultCondFailed      =  True
4427
            resultCondFailedCount += 1
4428
            ### Shrink interval for next iteration.
4429
            ub = lb + bw * onlyNullResultantsShrink
4430
            if ub > sdub:
4431
                ub = sdub
4432
            nbw = 0
4433
            continue
4434
        #### An intervalResultsList has at least the bounds.
4435
        globalResultsList.append(intervalResultsList)   
4436
        #### Compute an incremented width for next upper bound, only
4437
        #    if not Coppersmith condition nor resultant condition
4438
        #    failed at the previous run. 
4439
        if not coppCondFailed and not resultCondFailed:
4440
            nbw = noErrorIntervalStretch * bw
4441
        else:
4442
            nbw = bw
4443
        ##### Reset the failure flags. They will be raised
4444
        #     again if needed.
4445
        coppCondFailed   = False
4446
        resultCondFailed = False
4447
        #### For next iteration (at end of loop)
4448
        #print "nbw:", nbw
4449
        lb  = ub
4450
        ub += nbw     
4451
        if ub > sdub:
4452
            ub = sdub
4453
        print
4454
    # End while True
4455
    ## Main loop just ended.
4456
    globalWallTime = walltime(wallTimeStart)
4457
    globalCpuTime  = cputime(cpuTimeStart)
4458
    ## Output results
4459
    print ; print "Intervals and HTRNs" ; print
4460
    for intervalResultsList in globalResultsList:
4461
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
4462
                               "," + str(intervalResultsList[0][1])  + "]"
4463
        print intervalResultString,
4464
        if len(intervalResultsList) > 1:
4465
            rootsResultsList = intervalResultsList[1]
4466
            specificRootResultIndex = 0
4467
            for specificRootResultsList in rootsResultsList:
4468
                if specificRootResultIndex == 0:
4469
                    print "\t", specificRootResultsList[0],
4470
                else:
4471
                    print " " * len(intervalResultString), "\t", \
4472
                          specificRootResultsList[0],
4473
                if len(specificRootResultsList) > 1:
4474
                    print specificRootResultsList[1]
4475
                specificRootResultIndex += 1
4476
        print ; print
4477
    #print globalResultsList
4478
    #
4479
    print "Timers and counters"
4480
    print
4481
    print "Number of iterations:", iterCount
4482
    print "Taylor condition failures:", taylCondFailedCount
4483
    print "Coppersmith condition failures:", coppCondFailedCount
4484
    print "Resultant condition failures:", resultCondFailedCount
4485
    print "Iterations count: ", iterCount
4486
    print "Number of intervals:", len(globalResultsList)
4487
    print "Number of basis constructions:", basisConstructionsCount 
4488
    print "Total CPU time spent in basis constructions:", \
4489
        basisConstructionsFullTime
4490
    if basisConstructionsCount != 0:
4491
        print "Average basis construction CPU time:", \
4492
            basisConstructionsFullTime/basisConstructionsCount
4493
    print "Number of reductions:", reductionsCount
4494
    print "Total CPU time spent in reductions:", reductionsFullTime
4495
    if reductionsCount != 0:
4496
        print "Average reduction CPU time:", \
4497
            reductionsFullTime/reductionsCount
4498
    print "Number of resultants computation rounds:", \
4499
        resultantsComputationsCount
4500
    print "Total CPU time spent in resultants computation rounds:", \
4501
        resultantsComputationsFullTime
4502
    if resultantsComputationsCount != 0:
4503
        print "Average resultants computation round CPU time:", \
4504
            resultantsComputationsFullTime/resultantsComputationsCount
4505
    print "Number of root finding rounds:", rootsComputationsCount
4506
    print "Total CPU time spent in roots finding rounds:", \
4507
        rootsComputationsFullTime
4508
    if rootsComputationsCount != 0:
4509
        print "Average roots finding round CPU time:", \
4510
            rootsComputationsFullTime/rootsComputationsCount
4511
    print "Global Wall time:", globalWallTime
4512
    print "Global CPU time:", globalCpuTime
4513
    ## Output counters
4514
# End srs_runSLZ-v06
4515
sys.stderr.write("\t...sage Runtime SLZ loaded.\n")