Statistiques
| Révision :

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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