Statistiques
| Révision :

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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