Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (252,14 ko)

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

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

    
7
Examples:
8
    TODO
9
"""
10
sys.stderr.write("sage Runtime SLZ loading...\n")
11

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4035
    if debug:
4036
        print "Function                :", inputFunction
4037
        print "Lower bound             :", inputLowerBound.str(truncate=False)
4038
        print "Upper bounds            :", inputUpperBound.str(truncate=False)
4039
        print "Alpha                   :", alpha
4040
        print "Degree                  :", degree
4041
        print "Precision               :", precision
4042
        print "Emin                    :", emin
4043
        print "Emax                    :", emax
4044
        print "Target hardness-to-round:", targetHardnessToRound
4045
        print
4046
    ## Important constants.
4047
    ### Stretch the interval if no error happens.
4048
    noErrorIntervalStretch = 1 + 2^(-5)
4049
    ### If no vector validates the Coppersmith condition, shrink the interval
4050
    #   by the following factor.
4051
    noCoppersmithIntervalShrink = 1/2
4052
    ### If only (or at least) one vector validates the Coppersmith condition, 
4053
    #   shrink the interval by the following factor.
4054
    oneCoppersmithIntervalShrink = 3/4
4055
    #### If only null resultants are found, shrink the interval by the 
4056
    #    following factor.
4057
    onlyNullResultantsShrink     = 3/4
4058
    ## Structures.
4059
    RRR         = RealField(precision)
4060
    RRIF        = RealIntervalField(precision)
4061
    ## Converting input bound into the "right" field.
4062
    lowerBound = RRR(inputLowerBound)
4063
    upperBound = RRR(inputUpperBound)
4064
    ## Before going any further, check domain and image binade conditions.
4065
    print inputFunction._assume_str(), "at 1:", inputFunction(1).n()
4066
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
4067
    #print "srsv04p:", output, (output is None)
4068
    #
4069
    ## Check if input to thr fix_bounds function is valid.
4070
    if output is None:
4071
        print "Invalid domain/image binades. Domain:",\
4072
        lowerBound.str(truncate=False), upperBound(truncate=False), \
4073
        "Images:", \
4074
        inputFunction(lowerBound), inputFunction(upperBound)
4075
        raise Exception("Invalid domain/image binades.")
4076
    lb = output[0] ; ub = output[1]
4077
    #
4078
    ## Check if bounds have changed.
4079
    if lb != lowerBound or ub != upperBound:
4080
        print "lb:", lb.str(truncate=False), " - ub:", ub.str(truncate=False)
4081
        print "Invalid domain/image binades."
4082
        print "Domain:", lowerBound, upperBound
4083
        print "Images:", \
4084
        inputFunction(lowerBound), inputFunction(upperBound)
4085
        raise Exception("Invalid domain/image binades.")
4086
    #
4087
    ## Progam initialization
4088
    ### Approximation polynomial accuracy and hardness to round.
4089
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
4090
    #polyApproxAccur           = 2^(-(targetHardnessToRound + 12))
4091
    polyTargetHardnessToRound = targetHardnessToRound + 1
4092
    ### Significand to integer conversion ratio.
4093
    toIntegerFactor           = 2^(precision-1)
4094
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
4095
    ### Variables and rings for polynomials and root searching.
4096
    i=var('i')
4097
    t=var('t')
4098
    inputFunctionVariable = inputFunction.variables()[0]
4099
    function = inputFunction.subs({inputFunctionVariable:i})
4100
    #  Polynomial Rings over the integers, for root finding.
4101
    Zi = ZZ[i]
4102
    Zt = ZZ[t]
4103
    Zit = ZZ[i,t]
4104
    ## Number of iterations limit.
4105
    maxIter = 100000
4106
    #
4107
    ## Set the variable name in Sollya.
4108
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
4109
    ## Compute the scaled function and the degree, in their Sollya version 
4110
    #  once for all.
4111
    #print "srsvp initial bounds:",lowerBound, upperBound
4112
    (scaledf, sdlb, sdub, silb, siub) = \
4113
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
4114
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
4115
    #print "srsvp Scaled bounds:", sdlb, sdub
4116
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
4117
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
4118
    #
4119
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
4120
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
4121
    (unscalingFunction, scalingFunction) = \
4122
        slz_interval_scaling_expression(domainBoundsInterval, i)
4123
    #print scalingFunction, unscalingFunction
4124
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
4125
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
4126
    if internalSollyaPrec < 192:
4127
        internalSollyaPrec = 192
4128
    pobyso_set_prec_sa_so(internalSollyaPrec)
4129
    print "Sollya internal precision:", internalSollyaPrec
4130
    ## Some variables.
4131
    ### General variables
4132
    lb                  = sdlb
4133
    ub                  = sdub
4134
    nbw                 = 0
4135
    intervalUlp         = ub.ulp()
4136
    #### Will be set by slz_interval_and_polynomila_to_sage.
4137
    ic                  = 0 
4138
    icAsInt             = 0    # Set from ic.
4139
    solutionsSet        = set()
4140
    tsErrorWidth        = []
4141
    csErrorVectors      = []
4142
    csVectorsResultants = []
4143
    floatP              = 0  # Taylor polynomial.
4144
    floatPcv            = 0  # Ditto with variable change.
4145
    intvl               = "" # Taylor interval
4146
    terr                = 0  # Taylor error.
4147
    iterCount = 0
4148
    htrnSet = set()
4149
    ### Timers and counters.
4150
    wallTimeStart                   = 0
4151
    cpuTimeStart                    = 0
4152
    taylCondFailedCount             = 0
4153
    coppCondFailedCount             = 0
4154
    resultCondFailedCount           = 0
4155
    coppCondFailed                  = False
4156
    resultCondFailed                = False
4157
    globalResultsList               = []
4158
    basisConstructionsCount         = 0
4159
    basisConstructionsFullTime      = 0
4160
    basisConstructionTime           = 0
4161
    reductionsCount                 = 0
4162
    reductionsFullTime              = 0
4163
    reductionTime                   = 0
4164
    resultantsComputationsCount     = 0
4165
    resultantsComputationsFullTime  = 0
4166
    resultantsComputationTime       = 0
4167
    rootsComputationsCount          = 0
4168
    rootsComputationsFullTime       = 0
4169
    rootsComputationTime            = 0
4170
    print
4171
    ## Global times are started here.
4172
    wallTimeStart                   = walltime()
4173
    cpuTimeStart                    = cputime()
4174
    ## Main loop.
4175
    while True:
4176
        if lb >= sdub:
4177
            print "Lower bound reached upper bound."
4178
            break
4179
        if iterCount == maxIter:
4180
            print "Reached maxIter. Aborting"
4181
            break
4182
        iterCount += 1
4183
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4184
            "log2(numbers)." 
4185
        ### Compute a Sollya polynomial that will honor the Taylor condition.
4186
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
4187
                                                        degreeSo,
4188
                                                        lb,
4189
                                                        ub,
4190
                                                        polyApproxAccur,
4191
                                                        debug=debug)
4192
        if debug:
4193
            print "Approximation polynomial computed."
4194
        if prceSo is None:
4195
            raise Exception("Could not compute an approximation polynomial.")
4196
        ### Convert back the data into Sage space.                         
4197
        (floatP, floatPcv, intvl, ic, terr) = \
4198
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
4199
                                                 prceSo[1], prceSo[2], 
4200
                                                 prceSo[3]))
4201
        intvl = RRIF(intvl)
4202
        ## Clean-up Sollya stuff.
4203
        for elem in prceSo:
4204
            sollya_lib_clear_obj(elem)
4205
        #print  floatP, floatPcv, intvl, ic, terr
4206
        #print floatP
4207
        #print intvl.endpoints()[0].n(), \
4208
        #      ic.n(),
4209
        #intvl.endpoints()[1].n()
4210
        ### Check returned data.
4211
        #### Is approximation error OK?
4212
        if terr > polyApproxAccur:
4213
            exceptionErrorMess  = \
4214
                "Approximation failed - computed error:" + \
4215
                str(terr) + " - target error: "
4216
            exceptionErrorMess += \
4217
                str(polyApproxAccur) + ". Aborting!"
4218
            raise Exception(exceptionErrorMess)
4219
        #### Is lower bound OK?
4220
        if lb != intvl.endpoints()[0]:
4221
            exceptionErrorMess =  "Wrong lower bound:" + \
4222
                               str(lb) + ". Aborting!"
4223
            raise Exception(exceptionErrorMess)
4224
        #### Set upper bound.
4225
        if ub > intvl.endpoints()[1]:
4226
            ub = intvl.endpoints()[1]
4227
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4228
            "log2(numbers)." 
4229
            taylCondFailedCount += 1
4230
        #### Is interval not degenerate?
4231
        if lb >= ub:
4232
            exceptionErrorMess = "Degenerate interval: " + \
4233
                                "lowerBound(" + str(lb) +\
4234
                                ")>= upperBound(" + str(ub) + \
4235
                                "). Aborting!"
4236
            raise Exception(exceptionErrorMess)
4237
        #### Is interval center ok?
4238
        if ic <= lb or ic >= ub:
4239
            exceptionErrorMess =  "Invalid interval center for " + \
4240
                                str(lb) + ',' + str(ic) + ',' +  \
4241
                                str(ub) + ". Aborting!"
4242
            raise Exception(exceptionErrorMess)
4243
        ##### Current interval width and reset future interval width.
4244
        bw = ub - lb
4245
        nbw = 0
4246
        icAsInt = int(ic * toIntegerFactor)
4247
        #### The following ratio is always >= 1. In case we may want to
4248
        #    enlarge the interval
4249
        curTaylErrRat = polyApproxAccur / terr
4250
        ### Make the  integral transformations.
4251
        #### Bounds and interval center.
4252
        intIc = int(ic * toIntegerFactor)
4253
        intLb = int(lb * toIntegerFactor) - intIc
4254
        intUb = int(ub * toIntegerFactor) - intIc
4255
        #
4256
        #### Polynomials
4257
        basisConstructionTime         = cputime()
4258
        ##### To a polynomial with rational coefficients with rational arguments
4259
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
4260
        ##### To a polynomial with rational coefficients with integer arguments
4261
        ratIntP = \
4262
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
4263
        #####  Ultimately a multivariate polynomial with integer coefficients  
4264
        #      with integer arguments.
4265
        coppersmithTuple = \
4266
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
4267
                                                        precision, 
4268
                                                        targetHardnessToRound, 
4269
                                                        i, t)
4270
        #### Recover Coppersmith information.
4271
        intIntP = coppersmithTuple[0]
4272
        N = coppersmithTuple[1]
4273
        nAtAlpha = N^alpha
4274
        tBound = coppersmithTuple[2]
4275
        leastCommonMultiple = coppersmithTuple[3]
4276
        iBound = max(abs(intLb),abs(intUb))
4277
        basisConstructionsFullTime        += cputime(basisConstructionTime)
4278
        basisConstructionsCount           += 1
4279
        #### Compute the matrix to reduce for debug purpose. Otherwise
4280
        #    slz_compute_coppersmith_reduced_polynomials does the job
4281
        #    invisibly.
4282
        if debug:
4283
            matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
4284
                                                                alpha,
4285
                                                                N,
4286
                                                                iBound,
4287
                                                                tBound)
4288
            maxNorm     = 0
4289
            latticeSize = 0
4290
            matrixFile = file('/tmp/matrixToReduce.txt', 'w')
4291
            for row in matrixToReduce.rows():
4292
                currentNorm = row.norm()
4293
                if currentNorm > maxNorm:
4294
                    maxNorm = currentNorm
4295
                latticeSize += 1
4296
                for elem in row:
4297
                    matrixFile.write(elem.str(base=2) + ",")
4298
                matrixFile.write("\n")
4299
            #matrixFile.write(matrixToReduce.str(radix="2") + "\n")
4300
            matrixFile.close()
4301
            #### We use here binary length as defined in LLL princepts.
4302
            binaryLength = latticeSize * log(maxNorm)
4303
            print "Binary length:", binaryLength.n()
4304
            #raise Exception("Deliberate stop here.")
4305
        # End if debug
4306
        reductionTime                     = cputime()
4307
        #### Compute the reduced polynomials.
4308
        print "Starting reduction..."
4309
        ccReducedPolynomialsList =  \
4310
                slz_compute_coppersmith_reduced_polynomials_proj(intIntP, 
4311
                                                                 alpha, 
4312
                                                                 N, 
4313
                                                                 iBound, 
4314
                                                                 tBound)
4315
        print "...reduction accomplished in", cputime(reductionTime), "s."
4316
        if ccReducedPolynomialsList is None:
4317
            raise Exception("Reduction failed.")
4318
        reductionsFullTime    += cputime(reductionTime)
4319
        reductionsCount       += 1
4320
        if len(ccReducedPolynomialsList) < 2:
4321
            print "Nothing to form resultants with."
4322
            print
4323
            coppCondFailedCount += 1
4324
            coppCondFailed = True
4325
            ##### Apply a different shrink factor according to 
4326
            #  the number of compliant polynomials.
4327
            if len(ccReducedPolynomialsList) == 0:
4328
                ub = lb + bw * noCoppersmithIntervalShrink
4329
            else: # At least one compliant polynomial.
4330
                ub = lb + bw * oneCoppersmithIntervalShrink
4331
            if ub > sdub:
4332
                ub = sdub
4333
            if lb == ub:
4334
                raise Exception("Cant shrink interval \
4335
                anymore to get Coppersmith condition.")
4336
            nbw = 0
4337
            continue
4338
        #### We have at least two polynomials.
4339
        #    Let us try to compute resultants.
4340
        #    For each resultant computed, go for the solutions.
4341
        ##### Build the pairs list.
4342
        polyPairsList           = []
4343
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
4344
            for polyInnerIndex in xrange(polyOuterIndex+1, 
4345
                                         len(ccReducedPolynomialsList)):
4346
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
4347
                                      ccReducedPolynomialsList[polyInnerIndex]))
4348
        #### Actual root search.
4349
        iRootsSet           = set()
4350
        hasNonNullResultant = False
4351
        for polyPair in polyPairsList:
4352
            resultantsComputationTime = cputime()
4353
            currentResultantI = \
4354
                slz_resultant(polyPair[0],
4355
                              polyPair[1],
4356
                              t)
4357
            resultantsComputationsCount    += 1
4358
            resultantsComputationsFullTime +=  \
4359
                cputime(resultantsComputationTime)
4360
            #### Function slz_resultant returns None both for None and O
4361
            #    resultants.
4362
            if currentResultantI is None:
4363
                print "Nul resultant"
4364
                continue # Next polyPair.
4365
            ## We deleted the currentResultantI computation.
4366
            #### We have a non null resultant. From now on, whatever this
4367
            #    root search yields, no extra root search is necessary.
4368
            hasNonNullResultant = True
4369
            #### A constant resultant leads to no root. Root search is done.
4370
            if currentResultantI.degree() < 1:
4371
                print "Resultant is constant:", currentResultantI
4372
                break # There is no root.
4373
            #### Actual iroots computation.
4374
            rootsComputationTime        = cputime()
4375
            iRootsList = Zi(currentResultantI).roots()
4376
            rootsComputationsCount      +=  1
4377
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
4378
            if len(iRootsList) == 0:
4379
                print "No roots in \"i\"."
4380
                #break # No roots in i.
4381
            else:
4382
                for iRoot in iRootsList:
4383
                    # A root is given as a (value, multiplicity) tuple.
4384
                    iRootsSet.add(iRoot[0])
4385
                    print "Root added."
4386
            #### A non null, non constant resultant has been tested
4387
            #    for. There is no need to check for another one. Break
4388
            #    whether roots are found or not.
4389
            break
4390
        # End loop for polyPair in polyParsList. We only loop again if a 
4391
        # None or zero resultant is found.
4392
        #### Prepare for results for the current interval..
4393
        intervalResultsList = []
4394
        intervalResultsList.append((lb, ub))
4395
        #### Check roots.
4396
        rootsResultsList = []
4397
        for iRoot in iRootsSet:
4398
            specificRootResultsList = []
4399
            failingBounds           = []
4400
            # Root qualifies for modular equation, test it for hardness to round.
4401
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
4402
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
4403
            #print scalingFunction
4404
            scaledHardToRoundCaseAsFloat = \
4405
                scalingFunction(hardToRoundCaseAsFloat) 
4406
            print "Candidate HTRNc at x =", \
4407
                scaledHardToRoundCaseAsFloat.n().str(base=2),
4408
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
4409
                           function,
4410
                           2^-(targetHardnessToRound),
4411
                           RRR):
4412
                print hardToRoundCaseAsFloat, "is HTRN case."
4413
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
4414
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
4415
                    print "Found in interval."
4416
                else:
4417
                    print "Found out of interval."
4418
                # Check the i root is within the i bound.
4419
                if abs(iRoot) > iBound:
4420
                    print "IRoot", iRoot, "is out of bounds for modular equation."
4421
                    print "i bound:", iBound
4422
                    failingBounds.append('i')
4423
                    failingBounds.append(iRoot)
4424
                    failingBounds.append(iBound)
4425
                if len(failingBounds) > 0:
4426
                    specificRootResultsList.append(failingBounds)
4427
            else: # From slz_is_htrn...
4428
                print "is not an HTRN case."
4429
            if len(specificRootResultsList) > 0:
4430
                rootsResultsList.append(specificRootResultsList)
4431
        if len(rootsResultsList) > 0:
4432
            intervalResultsList.append(rootsResultsList)
4433
        ### Check if a non null resultant was found. If not shrink the interval.
4434
        if not hasNonNullResultant:
4435
            print "Only null resultants for this reduction, shrinking interval."
4436
            resultCondFailed      =  True
4437
            resultCondFailedCount += 1
4438
            ### Shrink interval for next iteration.
4439
            ub = lb + bw * onlyNullResultantsShrink
4440
            if ub > sdub:
4441
                ub = sdub
4442
            nbw = 0
4443
            continue
4444
        #### An intervalResultsList has at least the bounds.
4445
        globalResultsList.append(intervalResultsList)   
4446
        #### Compute an incremented width for next upper bound, only
4447
        #    if not Coppersmith condition nor resultant condition
4448
        #    failed at the previous run. 
4449
        if not coppCondFailed and not resultCondFailed:
4450
            nbw = noErrorIntervalStretch * bw
4451
        else:
4452
            nbw = bw
4453
        ##### Reset the failure flags. They will be raised
4454
        #     again if needed.
4455
        coppCondFailed   = False
4456
        resultCondFailed = False
4457
        #### For next iteration (at end of loop)
4458
        #print "nbw:", nbw
4459
        lb  = ub
4460
        ub += nbw     
4461
        if ub > sdub:
4462
            ub = sdub
4463
        print
4464
    # End while True
4465
    ## Main loop just ended.
4466
    globalWallTime = walltime(wallTimeStart)
4467
    globalCpuTime  = cputime(cpuTimeStart)
4468
    ## Output results
4469
    print ; print "Intervals and HTRNs" ; print
4470
    for intervalResultsList in globalResultsList:
4471
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
4472
                               "," + str(intervalResultsList[0][1])  + "]"
4473
        print intervalResultString,
4474
        if len(intervalResultsList) > 1:
4475
            rootsResultsList = intervalResultsList[1]
4476
            specificRootResultIndex = 0
4477
            for specificRootResultsList in rootsResultsList:
4478
                if specificRootResultIndex == 0:
4479
                    print "\t", specificRootResultsList[0],
4480
                else:
4481
                    print " " * len(intervalResultString), "\t", \
4482
                          specificRootResultsList[0],
4483
                if len(specificRootResultsList) > 1:
4484
                    print specificRootResultsList[1]
4485
                specificRootResultIndex += 1
4486
        print ; print
4487
    #print globalResultsList
4488
    #
4489
    print "Timers and counters"
4490
    print
4491
    print "Number of iterations:", iterCount
4492
    print "Taylor condition failures:", taylCondFailedCount
4493
    print "Coppersmith condition failures:", coppCondFailedCount
4494
    print "Resultant condition failures:", resultCondFailedCount
4495
    print "Iterations count: ", iterCount
4496
    print "Number of intervals:", len(globalResultsList)
4497
    print "Number of basis constructions:", basisConstructionsCount 
4498
    print "Total CPU time spent in basis constructions:", \
4499
        basisConstructionsFullTime
4500
    if basisConstructionsCount != 0:
4501
        print "Average basis construction CPU time:", \
4502
            basisConstructionsFullTime/basisConstructionsCount
4503
    print "Number of reductions:", reductionsCount
4504
    print "Total CPU time spent in reductions:", reductionsFullTime
4505
    if reductionsCount != 0:
4506
        print "Average reduction CPU time:", \
4507
            reductionsFullTime/reductionsCount
4508
    print "Number of resultants computation rounds:", \
4509
        resultantsComputationsCount
4510
    print "Total CPU time spent in resultants computation rounds:", \
4511
        resultantsComputationsFullTime
4512
    if resultantsComputationsCount != 0:
4513
        print "Average resultants computation round CPU time:", \
4514
            resultantsComputationsFullTime/resultantsComputationsCount
4515
    print "Number of root finding rounds:", rootsComputationsCount
4516
    print "Total CPU time spent in roots finding rounds:", \
4517
        rootsComputationsFullTime
4518
    if rootsComputationsCount != 0:
4519
        print "Average roots finding round CPU time:", \
4520
            rootsComputationsFullTime/rootsComputationsCount
4521
    print "Global Wall time:", globalWallTime
4522
    print "Global CPU time:", globalCpuTime
4523
    ## Output counters
4524
# End srs_runSLZ-v05_proj_02
4525
#
4526
def srs_run_SLZ_v05_proj_weak(inputFunction,
4527
                              inputLowerBound,
4528
                              inputUpperBound,
4529
                              alpha,
4530
                              degree,
4531
                              precision,
4532
                              emin,
4533
                              emax,
4534
                              targetHardnessToRound,
4535
                              debug = False):
4536
    """
4537
    chnages from v05_proj:
4538
       We use a weaker Coppersmith condition.
4539
    changes from plain V5:
4540
       LLL reduction is not performed on the matrix itself but rather on the
4541
       product of the matrix with a uniform random matrix.
4542
       The reduced matrix obtained is discarded but the transformation matrix 
4543
       obtained is used to multiply the original matrix in order to reduced it.
4544
       If a sufficient level of reduction is obtained, we stop here. If not
4545
       the product matrix obtained above is LLL reduced. But as it has been
4546
       pre-reduced at the above step, reduction is supposed to be much fastet.
4547
       In the worst case, both reductions combined should hopefully be faster 
4548
       than a straight single reduction.
4549
    Changes from V4:
4550
        Approximation polynomial has coefficients rounded.
4551
    Changes from V3:
4552
        Root search is changed again:
4553
            - only resultants in i are computed;
4554
            - roots in i are searched for;
4555
            - if any, they are tested for hardness-to-round.
4556
    Changes from V2:
4557
        Root search is changed:
4558
            - we compute the resultants in i and in t;
4559
            - we compute the roots set of each of these resultants;
4560
            - we combine all the possible pairs between the two sets;
4561
            - we check these pairs in polynomials for correctness.
4562
    Changes from V1: 
4563
        1- check for roots as soon as a resultant is computed;
4564
        2- once a non null resultant is found, check for roots;
4565
        3- constant resultant == no root.
4566
    """
4567

    
4568
    if debug:
4569
        print "Function                :", inputFunction
4570
        print "Lower bound             :", inputLowerBound.str(truncate=False)
4571
        print "Upper bounds            :", inputUpperBound.str(truncate=False)
4572
        print "Alpha                   :", alpha
4573
        print "Degree                  :", degree
4574
        print "Precision               :", precision
4575
        print "Emin                    :", emin
4576
        print "Emax                    :", emax
4577
        print "Target hardness-to-round:", targetHardnessToRound
4578
        print
4579
    ## Important constants.
4580
    ### Stretch the interval if no error happens.
4581
    noErrorIntervalStretch = 1 + 2^(-5)
4582
    ### If no vector validates the Coppersmith condition, shrink the interval
4583
    #   by the following factor.
4584
    noCoppersmithIntervalShrink = 1/2
4585
    ### If only (or at least) one vector validates the Coppersmith condition, 
4586
    #   shrink the interval by the following factor.
4587
    oneCoppersmithIntervalShrink = 3/4
4588
    #### If only null resultants are found, shrink the interval by the 
4589
    #    following factor.
4590
    onlyNullResultantsShrink     = 3/4
4591
    ## Structures.
4592
    RRR         = RealField(precision)
4593
    RRIF        = RealIntervalField(precision)
4594
    ## Converting input bound into the "right" field.
4595
    lowerBound = RRR(inputLowerBound)
4596
    upperBound = RRR(inputUpperBound)
4597
    ## Before going any further, check domain and image binade conditions.
4598
    print inputFunction._assume_str(), "at 1:", inputFunction(1).n()
4599
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
4600
    #print "srsv04p:", output, (output is None)
4601
    #
4602
    ## Check if input to thr fix_bounds function is valid.
4603
    if output is None:
4604
        print "Invalid domain/image binades. Domain:",\
4605
        lowerBound.str(truncate=False), upperBound(truncate=False), \
4606
        "Images:", \
4607
        inputFunction(lowerBound), inputFunction(upperBound)
4608
        raise Exception("Invalid domain/image binades.")
4609
    lb = output[0] ; ub = output[1]
4610
    #
4611
    ## Check if bounds have changed.
4612
    if lb != lowerBound or ub != upperBound:
4613
        print "lb:", lb.str(truncate=False), " - ub:", ub.str(truncate=False)
4614
        print "Invalid domain/image binades."
4615
        print "Domain:", lowerBound, upperBound
4616
        print "Images:", \
4617
        inputFunction(lowerBound), inputFunction(upperBound)
4618
        raise Exception("Invalid domain/image binades.")
4619
    #
4620
    ## Progam initialization
4621
    ### Approximation polynomial accuracy and hardness to round.
4622
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
4623
    #polyApproxAccur           = 2^(-(targetHardnessToRound + 12))
4624
    polyTargetHardnessToRound = targetHardnessToRound + 1
4625
    ### Significand to integer conversion ratio.
4626
    toIntegerFactor           = 2^(precision-1)
4627
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
4628
    ### Variables and rings for polynomials and root searching.
4629
    i=var('i')
4630
    t=var('t')
4631
    inputFunctionVariable = inputFunction.variables()[0]
4632
    function = inputFunction.subs({inputFunctionVariable:i})
4633
    #  Polynomial Rings over the integers, for root finding.
4634
    Zi = ZZ[i]
4635
    Zt = ZZ[t]
4636
    Zit = ZZ[i,t]
4637
    ## Number of iterations limit.
4638
    maxIter = 100000
4639
    #
4640
    ## Set the variable name in Sollya.
4641
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
4642
    ## Compute the scaled function and the degree, in their Sollya version 
4643
    #  once for all.
4644
    #print "srsvp initial bounds:",lowerBound, upperBound
4645
    (scaledf, sdlb, sdub, silb, siub) = \
4646
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
4647
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
4648
    #print "srsvp Scaled bounds:", sdlb, sdub
4649
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
4650
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
4651
    #
4652
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
4653
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
4654
    (unscalingFunction, scalingFunction) = \
4655
        slz_interval_scaling_expression(domainBoundsInterval, i)
4656
    #print scalingFunction, unscalingFunction
4657
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
4658
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
4659
    if internalSollyaPrec < 192:
4660
        internalSollyaPrec = 192
4661
    pobyso_set_prec_sa_so(internalSollyaPrec)
4662
    print "Sollya internal precision:", internalSollyaPrec
4663
    ## Some variables.
4664
    ### General variables
4665
    lb                  = sdlb
4666
    ub                  = sdub
4667
    nbw                 = 0
4668
    intervalUlp         = ub.ulp()
4669
    #### Will be set by slz_interval_and_polynomila_to_sage.
4670
    ic                  = 0 
4671
    icAsInt             = 0    # Set from ic.
4672
    solutionsSet        = set()
4673
    tsErrorWidth        = []
4674
    csErrorVectors      = []
4675
    csVectorsResultants = []
4676
    floatP              = 0  # Taylor polynomial.
4677
    floatPcv            = 0  # Ditto with variable change.
4678
    intvl               = "" # Taylor interval
4679
    terr                = 0  # Taylor error.
4680
    iterCount = 0
4681
    htrnSet = set()
4682
    ### Timers and counters.
4683
    wallTimeStart                   = 0
4684
    cpuTimeStart                    = 0
4685
    taylCondFailedCount             = 0
4686
    coppCondFailedCount             = 0
4687
    resultCondFailedCount           = 0
4688
    coppCondFailed                  = False
4689
    resultCondFailed                = False
4690
    globalResultsList               = []
4691
    basisConstructionsCount         = 0
4692
    basisConstructionsFullTime      = 0
4693
    basisConstructionTime           = 0
4694
    reductionsCount                 = 0
4695
    reductionsFullTime              = 0
4696
    reductionTime                   = 0
4697
    resultantsComputationsCount     = 0
4698
    resultantsComputationsFullTime  = 0
4699
    resultantsComputationTime       = 0
4700
    rootsComputationsCount          = 0
4701
    rootsComputationsFullTime       = 0
4702
    rootsComputationTime            = 0
4703
    print
4704
    ## Global times are started here.
4705
    wallTimeStart                   = walltime()
4706
    cpuTimeStart                    = cputime()
4707
    ## Main loop.
4708
    while True:
4709
        if lb >= sdub:
4710
            print "Lower bound reached upper bound."
4711
            break
4712
        if iterCount == maxIter:
4713
            print "Reached maxIter. Aborting"
4714
            break
4715
        iterCount += 1
4716
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4717
            "log2(numbers)." 
4718
        ### Compute a Sollya polynomial that will honor the Taylor condition.
4719
        prceSo = slz_compute_polynomial_and_interval_01(scaledfSo,
4720
                                                        degreeSo,
4721
                                                        lb,
4722
                                                        ub,
4723
                                                        polyApproxAccur,
4724
                                                        debug=debug)
4725
        if debug:
4726
            print "Approximation polynomial computed."
4727
        if prceSo is None:
4728
            raise Exception("Could not compute an approximation polynomial.")
4729
        ### Convert back the data into Sage space.                         
4730
        (floatP, floatPcv, intvl, ic, terr) = \
4731
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
4732
                                                 prceSo[1], prceSo[2], 
4733
                                                 prceSo[3]))
4734
        intvl = RRIF(intvl)
4735
        ## Clean-up Sollya stuff.
4736
        for elem in prceSo:
4737
            sollya_lib_clear_obj(elem)
4738
        #print  floatP, floatPcv, intvl, ic, terr
4739
        #print floatP
4740
        #print intvl.endpoints()[0].n(), \
4741
        #      ic.n(),
4742
        #intvl.endpoints()[1].n()
4743
        ### Check returned data.
4744
        #### Is approximation error OK?
4745
        if terr > polyApproxAccur:
4746
            exceptionErrorMess  = \
4747
                "Approximation failed - computed error:" + \
4748
                str(terr) + " - target error: "
4749
            exceptionErrorMess += \
4750
                str(polyApproxAccur) + ". Aborting!"
4751
            raise Exception(exceptionErrorMess)
4752
        #### Is lower bound OK?
4753
        if lb != intvl.endpoints()[0]:
4754
            exceptionErrorMess =  "Wrong lower bound:" + \
4755
                               str(lb) + ". Aborting!"
4756
            raise Exception(exceptionErrorMess)
4757
        #### Set upper bound.
4758
        if ub > intvl.endpoints()[1]:
4759
            ub = intvl.endpoints()[1]
4760
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
4761
            "log2(numbers)." 
4762
            taylCondFailedCount += 1
4763
        #### Is interval not degenerate?
4764
        if lb >= ub:
4765
            exceptionErrorMess = "Degenerate interval: " + \
4766
                                "lowerBound(" + str(lb) +\
4767
                                ")>= upperBound(" + str(ub) + \
4768
                                "). Aborting!"
4769
            raise Exception(exceptionErrorMess)
4770
        #### Is interval center ok?
4771
        if ic <= lb or ic >= ub:
4772
            exceptionErrorMess =  "Invalid interval center for " + \
4773
                                str(lb) + ',' + str(ic) + ',' +  \
4774
                                str(ub) + ". Aborting!"
4775
            raise Exception(exceptionErrorMess)
4776
        ##### Current interval width and reset future interval width.
4777
        bw = ub - lb
4778
        nbw = 0
4779
        icAsInt = int(ic * toIntegerFactor)
4780
        #### The following ratio is always >= 1. In case we may want to
4781
        #    enlarge the interval
4782
        curTaylErrRat = polyApproxAccur / terr
4783
        ### Make the  integral transformations.
4784
        #### Bounds and interval center.
4785
        intIc = int(ic * toIntegerFactor)
4786
        intLb = int(lb * toIntegerFactor) - intIc
4787
        intUb = int(ub * toIntegerFactor) - intIc
4788
        #
4789
        #### Polynomials
4790
        basisConstructionTime         = cputime()
4791
        ##### To a polynomial with rational coefficients with rational arguments
4792
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
4793
        ##### To a polynomial with rational coefficients with integer arguments
4794
        ratIntP = \
4795
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
4796
        #####  Ultimately a multivariate polynomial with integer coefficients  
4797
        #      with integer arguments.
4798
        coppersmithTuple = \
4799
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
4800
                                                        precision, 
4801
                                                        targetHardnessToRound, 
4802
                                                        i, t)
4803
        #### Recover Coppersmith information.
4804
        intIntP = coppersmithTuple[0]
4805
        N = coppersmithTuple[1]
4806
        nAtAlpha = N^alpha
4807
        tBound = coppersmithTuple[2]
4808
        leastCommonMultiple = coppersmithTuple[3]
4809
        iBound = max(abs(intLb),abs(intUb))
4810
        basisConstructionsFullTime        += cputime(basisConstructionTime)
4811
        basisConstructionsCount           += 1
4812
        #### Compute the matrix to reduce for debug purpose. Otherwise
4813
        #    slz_compute_coppersmith_reduced_polynomials does the job
4814
        #    invisibly.
4815
        if debug:
4816
            matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
4817
                                                                alpha,
4818
                                                                N,
4819
                                                                iBound,
4820
                                                                tBound)
4821
            maxNorm     = 0
4822
            latticeSize = 0
4823
            matrixFile = file('/tmp/matrixToReduce.txt', 'w')
4824
            for row in matrixToReduce.rows():
4825
                currentNorm = row.norm()
4826
                if currentNorm > maxNorm:
4827
                    maxNorm = currentNorm
4828
                latticeSize += 1
4829
                for elem in row:
4830
                    matrixFile.write(elem.str(base=2) + ",")
4831
                matrixFile.write("\n")
4832
            #matrixFile.write(matrixToReduce.str(radix="2") + "\n")
4833
            matrixFile.close()
4834
            #### We use here binary length as defined in LLL princepts.
4835
            binaryLength = latticeSize * log(maxNorm)
4836
            print "Binary length:", binaryLength.n()
4837
            #raise Exception("Deliberate stop here.")
4838
        # End if debug
4839
        reductionTime                     = cputime()
4840
        #### Compute the reduced polynomials.
4841
        print "Starting reduction..."
4842
        ccReducedPolynomialsList =  \
4843
                slz_compute_weak_coppersmith_reduced_polynomials_proj(intIntP, 
4844
                                                                      alpha, 
4845
                                                                      N, 
4846
                                                                      iBound, 
4847
                                                                      tBound)
4848
        print "...reduction accomplished in", cputime(reductionTime), "s."
4849
        if ccReducedPolynomialsList is None:
4850
            raise Exception("Reduction failed.")
4851
        reductionsFullTime    += cputime(reductionTime)
4852
        reductionsCount       += 1
4853
        if len(ccReducedPolynomialsList) < 2:
4854
            print "Nothing to form resultants with."
4855
            print
4856
            coppCondFailedCount += 1
4857
            coppCondFailed = True
4858
            ##### Apply a different shrink factor according to 
4859
            #  the number of compliant polynomials.
4860
            if len(ccReducedPolynomialsList) == 0:
4861
                ub = lb + bw * noCoppersmithIntervalShrink
4862
            else: # At least one compliant polynomial.
4863
                ub = lb + bw * oneCoppersmithIntervalShrink
4864
            if ub > sdub:
4865
                ub = sdub
4866
            if lb == ub:
4867
                raise Exception("Cant shrink interval \
4868
                anymore to get Coppersmith condition.")
4869
            nbw = 0
4870
            continue
4871
        #### We have at least two polynomials.
4872
        #    Let us try to compute resultants.
4873
        #    For each resultant computed, go for the solutions.
4874
        ##### Build the pairs list.
4875
        polyPairsList           = []
4876
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
4877
            for polyInnerIndex in xrange(polyOuterIndex+1, 
4878
                                         len(ccReducedPolynomialsList)):
4879
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
4880
                                      ccReducedPolynomialsList[polyInnerIndex]))
4881
        #### Actual root search.
4882
        iRootsSet           = set()
4883
        hasNonNullResultant = False
4884
        for polyPair in polyPairsList:
4885
            resultantsComputationTime = cputime()
4886
            currentResultantI = \
4887
                slz_resultant(polyPair[0],
4888
                              polyPair[1],
4889
                              t)
4890
            resultantsComputationsCount    += 1
4891
            resultantsComputationsFullTime +=  \
4892
                cputime(resultantsComputationTime)
4893
            #### Function slz_resultant returns None both for None and O
4894
            #    resultants.
4895
            if currentResultantI is None:
4896
                print "Nul resultant"
4897
                continue # Next polyPair.
4898
            ## We deleted the currentResultantI computation.
4899
            #### We have a non null resultant. From now on, whatever this
4900
            #    root search yields, no extra root search is necessary.
4901
            hasNonNullResultant = True
4902
            #### A constant resultant leads to no root. Root search is done.
4903
            if currentResultantI.degree() < 1:
4904
                print "Resultant is constant:", currentResultantI
4905
                break # There is no root.
4906
            #### Actual iroots computation.
4907
            rootsComputationTime        = cputime()
4908
            iRootsList = Zi(currentResultantI).roots()
4909
            rootsComputationsCount      +=  1
4910
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
4911
            if len(iRootsList) == 0:
4912
                print "No roots in \"i\"."
4913
                #break # No roots in i.
4914
            else:
4915
                for iRoot in iRootsList:
4916
                    # A root is given as a (value, multiplicity) tuple.
4917
                    iRootsSet.add(iRoot[0])
4918
                    print "Root added."
4919
            #### A non null, non constant resultant has been tested
4920
            #    for. There is no need to check for another one. Break
4921
            #    whether roots are found or not.
4922
            break
4923
        # End loop for polyPair in polyParsList. We only loop again if a 
4924
        # None or zero resultant is found.
4925
        #### Prepare for results for the current interval..
4926
        intervalResultsList = []
4927
        intervalResultsList.append((lb, ub))
4928
        #### Check roots.
4929
        rootsResultsList = []
4930
        for iRoot in iRootsSet:
4931
            specificRootResultsList = []
4932
            failingBounds           = []
4933
            # Root qualifies for modular equation, test it for hardness to round.
4934
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
4935
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
4936
            #print scalingFunction
4937
            scaledHardToRoundCaseAsFloat = \
4938
                scalingFunction(hardToRoundCaseAsFloat) 
4939
            print "Candidate HTRNc at x =", \
4940
                scaledHardToRoundCaseAsFloat.n().str(base=2),
4941
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
4942
                           function,
4943
                           2^-(targetHardnessToRound),
4944
                           RRR):
4945
                print hardToRoundCaseAsFloat, "is HTRN case."
4946
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
4947
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
4948
                    print "Found in interval."
4949
                else:
4950
                    print "Found out of interval."
4951
                # Check the i root is within the i bound.
4952
                if abs(iRoot) > iBound:
4953
                    print "IRoot", iRoot, "is out of bounds for modular equation."
4954
                    print "i bound:", iBound
4955
                    failingBounds.append('i')
4956
                    failingBounds.append(iRoot)
4957
                    failingBounds.append(iBound)
4958
                if len(failingBounds) > 0:
4959
                    specificRootResultsList.append(failingBounds)
4960
            else: # From slz_is_htrn...
4961
                print "is not an HTRN case."
4962
            if len(specificRootResultsList) > 0:
4963
                rootsResultsList.append(specificRootResultsList)
4964
        if len(rootsResultsList) > 0:
4965
            intervalResultsList.append(rootsResultsList)
4966
        ### Check if a non null resultant was found. If not shrink the interval.
4967
        if not hasNonNullResultant:
4968
            print "Only null resultants for this reduction, shrinking interval."
4969
            resultCondFailed      =  True
4970
            resultCondFailedCount += 1
4971
            ### Shrink interval for next iteration.
4972
            ub = lb + bw * onlyNullResultantsShrink
4973
            if ub > sdub:
4974
                ub = sdub
4975
            nbw = 0
4976
            continue
4977
        #### An intervalResultsList has at least the bounds.
4978
        globalResultsList.append(intervalResultsList)   
4979
        #### Compute an incremented width for next upper bound, only
4980
        #    if not Coppersmith condition nor resultant condition
4981
        #    failed at the previous run. 
4982
        if not coppCondFailed and not resultCondFailed:
4983
            nbw = noErrorIntervalStretch * bw
4984
        else:
4985
            nbw = bw
4986
        ##### Reset the failure flags. They will be raised
4987
        #     again if needed.
4988
        coppCondFailed   = False
4989
        resultCondFailed = False
4990
        #### For next iteration (at end of loop)
4991
        #print "nbw:", nbw
4992
        lb  = ub
4993
        ub += nbw     
4994
        if ub > sdub:
4995
            ub = sdub
4996
        print
4997
    # End while True
4998
    ## Main loop just ended.
4999
    globalWallTime = walltime(wallTimeStart)
5000
    globalCpuTime  = cputime(cpuTimeStart)
5001
    ## Output results
5002
    print ; print "Intervals and HTRNs" ; print
5003
    for intervalResultsList in globalResultsList:
5004
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
5005
                               "," + str(intervalResultsList[0][1])  + "]"
5006
        print intervalResultString,
5007
        if len(intervalResultsList) > 1:
5008
            rootsResultsList = intervalResultsList[1]
5009
            specificRootResultIndex = 0
5010
            for specificRootResultsList in rootsResultsList:
5011
                if specificRootResultIndex == 0:
5012
                    print "\t", specificRootResultsList[0],
5013
                else:
5014
                    print " " * len(intervalResultString), "\t", \
5015
                          specificRootResultsList[0],
5016
                if len(specificRootResultsList) > 1:
5017
                    print specificRootResultsList[1]
5018
                specificRootResultIndex += 1
5019
        print ; print
5020
    #print globalResultsList
5021
    #
5022
    print "Timers and counters"
5023
    print
5024
    print "Number of iterations:", iterCount
5025
    print "Taylor condition failures:", taylCondFailedCount
5026
    print "Coppersmith condition failures:", coppCondFailedCount
5027
    print "Resultant condition failures:", resultCondFailedCount
5028
    print "Iterations count: ", iterCount
5029
    print "Number of intervals:", len(globalResultsList)
5030
    print "Number of basis constructions:", basisConstructionsCount 
5031
    print "Total CPU time spent in basis constructions:", \
5032
        basisConstructionsFullTime
5033
    if basisConstructionsCount != 0:
5034
        print "Average basis construction CPU time:", \
5035
            basisConstructionsFullTime/basisConstructionsCount
5036
    print "Number of reductions:", reductionsCount
5037
    print "Total CPU time spent in reductions:", reductionsFullTime
5038
    if reductionsCount != 0:
5039
        print "Average reduction CPU time:", \
5040
            reductionsFullTime/reductionsCount
5041
    print "Number of resultants computation rounds:", \
5042
        resultantsComputationsCount
5043
    print "Total CPU time spent in resultants computation rounds:", \
5044
        resultantsComputationsFullTime
5045
    if resultantsComputationsCount != 0:
5046
        print "Average resultants computation round CPU time:", \
5047
            resultantsComputationsFullTime/resultantsComputationsCount
5048
    print "Number of root finding rounds:", rootsComputationsCount
5049
    print "Total CPU time spent in roots finding rounds:", \
5050
        rootsComputationsFullTime
5051
    if rootsComputationsCount != 0:
5052
        print "Average roots finding round CPU time:", \
5053
            rootsComputationsFullTime/rootsComputationsCount
5054
    print "Global Wall time:", globalWallTime
5055
    print "Global CPU time:", globalCpuTime
5056
    ## Output counters
5057
# End srs_runSLZ-v05_proj
5058
#
5059
def srs_run_SLZ_v06(inputFunction,
5060
                    inputLowerBound,
5061
                    inputUpperBound,
5062
                    alpha,
5063
                    degree,
5064
                    precision,
5065
                    emin,
5066
                    emax,
5067
                    targetHardnessToRound,
5068
                    debug = True):
5069
    """
5070
    Changes from V5:
5071
        Very verbose
5072
    Changes from V4:
5073
        Approximation polynomial has coefficients rounded.
5074
    Changes from V3:
5075
        Root search is changed again:
5076
            - only resultants in i are computed;
5077
            - roots in i are searched for;
5078
            - if any, they are tested for hardness-to-round.
5079
    Changes from V2:
5080
        Root search is changed:
5081
            - we compute the resultants in i and in t;
5082
            - we compute the roots set of each of these resultants;
5083
            - we combine all the possible pairs between the two sets;
5084
            - we check these pairs in polynomials for correctness.
5085
    Changes from V1: 
5086
        1- check for roots as soon as a resultant is computed;
5087
        2- once a non null resultant is found, check for roots;
5088
        3- constant resultant == no root.
5089
    """
5090
    if debug:
5091
        print "Function                :", inputFunction
5092
        print "Lower bound             :", inputLowerBound
5093
        print "Upper bounds            :", inputUpperBound
5094
        print "Alpha                   :", alpha
5095
        print "Degree                  :", degree
5096
        print "Precision               :", precision
5097
        print "Emin                    :", emin
5098
        print "Emax                    :", emax
5099
        print "Target hardness-to-round:", targetHardnessToRound
5100
        print
5101
    ## Important constants.
5102
    ### Stretch the interval if no error happens.
5103
    noErrorIntervalStretch = 1 + 2^(-5)
5104
    ### If no vector validates the Coppersmith condition, shrink the interval
5105
    #   by the following factor.
5106
    noCoppersmithIntervalShrink = 1/2
5107
    ### If only (or at least) one vector validates the Coppersmith condition, 
5108
    #   shrink the interval by the following factor.
5109
    oneCoppersmithIntervalShrink = 3/4
5110
    #### If only null resultants are found, shrink the interval by the 
5111
    #    following factor.
5112
    onlyNullResultantsShrink     = 3/4
5113
    ## Structures.
5114
    RRR         = RealField(precision)
5115
    RRIF        = RealIntervalField(precision)
5116
    ## Converting input bound into the "right" field.
5117
    lowerBound = RRR(inputLowerBound)
5118
    upperBound = RRR(inputUpperBound)
5119
    ## Before going any further, check domain and image binade conditions.
5120
    print inputFunction(1).n()
5121
    output = slz_fix_bounds_for_binades(lowerBound, upperBound, inputFunction)
5122
    if output is None:
5123
        print "Invalid domain/image binades. Domain:",\
5124
        lowerBound, upperBound, "Images:", \
5125
        inputFunction(lowerBound), inputFunction(upperBound)
5126
        raise Exception("Invalid domain/image binades.")
5127
    lb = output[0] ; ub = output[1]
5128
    if lb != lowerBound or ub != upperBound:
5129
        print "lb:", lb, " - ub:", ub
5130
        print "Invalid domain/image binades. Domain:",\
5131
        lowerBound, upperBound, "Images:", \
5132
        inputFunction(lowerBound), inputFunction(upperBound)
5133
        raise Exception("Invalid domain/image binades.")
5134
    #
5135
    ## Progam initialization
5136
    ### Approximation polynomial accuracy and hardness to round.
5137
    polyApproxAccur           = 2^(-(targetHardnessToRound + 1))
5138
    polyTargetHardnessToRound = targetHardnessToRound + 1
5139
    ### Significand to integer conversion ratio.
5140
    toIntegerFactor           = 2^(precision-1)
5141
    print "Polynomial approximation required accuracy:", polyApproxAccur.n()
5142
    ### Variables and rings for polynomials and root searching.
5143
    i=var('i')
5144
    t=var('t')
5145
    inputFunctionVariable = inputFunction.variables()[0]
5146
    function = inputFunction.subs({inputFunctionVariable:i})
5147
    #  Polynomial Rings over the integers, for root finding.
5148
    Zi = ZZ[i]
5149
    ## Number of iterations limit.
5150
    maxIter = 100000
5151
    #
5152
    ## Set the variable name in Sollya.
5153
    pobyso_name_free_variable_sa_so(str(function.variables()[0]))
5154
    ## Compute the scaled function and the degree, in their Sollya version 
5155
    #  once for all.
5156
    (scaledf, sdlb, sdub, silb, siub) = \
5157
        slz_compute_scaled_function(function, lowerBound, upperBound, precision)
5158
    print "Scaled function:", scaledf._assume_str().replace('_SAGE_VAR_', '')
5159
    scaledfSo = sollya_lib_parse_string(scaledf._assume_str().replace('_SAGE_VAR_', ''))
5160
    degreeSo  = pobyso_constant_from_int_sa_so(degree)
5161
    #
5162
    ## Compute the scaling. boundsIntervalRifSa defined out of the loops.
5163
    domainBoundsInterval   = RRIF(lowerBound, upperBound)
5164
    (unscalingFunction, scalingFunction) = \
5165
        slz_interval_scaling_expression(domainBoundsInterval, i)
5166
    #print scalingFunction, unscalingFunction
5167
    ## Set the Sollya internal precision (with an arbitrary minimum of 192).
5168
    internalSollyaPrec = ceil((RR('1.5') * targetHardnessToRound) / 64) * 64
5169
    if internalSollyaPrec < 192:
5170
        internalSollyaPrec = 192
5171
    pobyso_lib_init()
5172
    pobyso_set_prec_sa_so(internalSollyaPrec)
5173
    print "Sollya internal precision:", internalSollyaPrec
5174
    targetPlusOnePrecRF       = RealField(RRR.prec()+1)
5175
    if internalSollyaPrec < 1024:
5176
        quasiExactRF              = RealField(1014)
5177
    else:
5178
        quasiExactRF              = RealField(internalSollyaPrec) 
5179
    ## Some variables.
5180
    ### General variables
5181
    lb                  = sdlb
5182
    ub                  = sdub
5183
    nbw                 = 0
5184
    intervalUlp         = ub.ulp()
5185
    #### Will be set by slz_interval_and_polynomila_to_sage.
5186
    ic                  = 0 
5187
    icAsInt             = 0    # Set from ic.
5188
    solutionsSet        = set()
5189
    tsErrorWidth        = []
5190
    csErrorVectors      = []
5191
    csVectorsResultants = []
5192
    floatP              = 0  # Taylor polynomial.
5193
    floatPcv            = 0  # Ditto with variable change.
5194
    intvl               = "" # Taylor interval
5195
    terr                = 0  # Taylor error.
5196
    iterCount = 0
5197
    htrnSet = set()
5198
    ### Timers and counters.
5199
    wallTimeStart                   = 0
5200
    cpuTimeStart                    = 0
5201
    taylCondFailedCount             = 0
5202
    coppCondFailedCount             = 0
5203
    resultCondFailedCount           = 0
5204
    coppCondFailed                  = False
5205
    resultCondFailed                = False
5206
    globalResultsList               = []
5207
    basisConstructionsCount         = 0
5208
    basisConstructionsFullTime      = 0
5209
    basisConstructionTime           = 0
5210
    reductionsCount                 = 0
5211
    reductionsFullTime              = 0
5212
    reductionTime                   = 0
5213
    resultantsComputationsCount     = 0
5214
    resultantsComputationsFullTime  = 0
5215
    resultantsComputationTime       = 0
5216
    rootsComputationsCount          = 0
5217
    rootsComputationsFullTime       = 0
5218
    rootsComputationTime            = 0
5219
    print
5220
    ## Global times are started here.
5221
    wallTimeStart                   = walltime()
5222
    cpuTimeStart                    = cputime()
5223
    ## Main loop.
5224
    while True:
5225
        if lb >= sdub:
5226
            print "Lower bound reached upper bound."
5227
            break
5228
        if iterCount == maxIter:
5229
            print "Reached maxIter. Aborting"
5230
            break
5231
        iterCount += 1
5232
        print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
5233
            "log2(numbers)." 
5234
        #print "Debugging..."
5235
        ### Compute a Sollya polynomial that will honor the Taylor condition.
5236
        prceSo = slz_compute_polynomial_and_interval_02(scaledfSo,
5237
                                                        degreeSo,
5238
                                                        lb,
5239
                                                        ub,
5240
                                                        polyApproxAccur,
5241
                                                        debug=True)
5242
        if debug:
5243
            print "Sollya Taylor polynomial:", ; pobyso_autoprint(prceSo[0])
5244
            print "Sollya interval         :", ; pobyso_autoprint(prceSo[1])
5245
            print "Sollya interval center  :", ; pobyso_autoprint(prceSo[2])
5246
            print "Sollya Taylor error     :", ; pobyso_autoprint(prceSo[3])
5247

    
5248
        ### Convert back the data into Sage space.                         
5249
        (floatP, floatPcv, intvl, ic, terr) = \
5250
            slz_interval_and_polynomial_to_sage((prceSo[0], prceSo[0],
5251
                                                 prceSo[1], prceSo[2], 
5252
                                                 prceSo[3]))
5253
        print "Sage Taylor polynomial:", floatP, floatP.parent()
5254
        floatPcoeffs = floatP.coefficients()
5255
        for coeff in floatPcoeffs:
5256
            print coeff.n(prec=coeff.parent().prec()).str(base=2)
5257
            print coeff.n(prec=coeff.parent().prec())
5258
        intvl = RRIF(intvl)
5259
        ## Clean-up Sollya stuff.
5260
        for elem in prceSo:
5261
            sollya_lib_clear_obj(elem)
5262
        #print  floatP, floatPcv, intvl, ic, terr
5263
        #print floatP
5264
        #print intvl.endpoints()[0].n(), \
5265
        #      ic.n(),
5266
        #intvl.endpoints()[1].n()
5267
        ### Check returned data.
5268
        #### Is approximation error OK?
5269
        if terr > polyApproxAccur:
5270
            exceptionErrorMess  = \
5271
                "Approximation failed - computed error:" + \
5272
                str(terr) + " - target error: "
5273
            exceptionErrorMess += \
5274
                str(polyApproxAccur) + ". Aborting!"
5275
            raise Exception(exceptionErrorMess)
5276
        #### Is lower bound OK?
5277
        if lb != intvl.endpoints()[0]:
5278
            exceptionErrorMess =  "Wrong lower bound:" + \
5279
                               str(lb) + ". Aborting!"
5280
            raise Exception(exceptionErrorMess)
5281
        #### Set upper bound.
5282
        if ub > intvl.endpoints()[1]:
5283
            ub = intvl.endpoints()[1]
5284
            print "[", lb, ",", ub, "]", ((ub - lb) / intervalUlp).log2().n(), \
5285
            "log2(numbers)." 
5286
            taylCondFailedCount += 1
5287
        #### Is interval not degenerate?
5288
        if lb >= ub:
5289
            exceptionErrorMess = "Degenerate interval: " + \
5290
                                "lowerBound(" + str(lb) +\
5291
                                ")>= upperBound(" + str(ub) + \
5292
                                "). Aborting!"
5293
            raise Exception(exceptionErrorMess)
5294
        #### Is interval center ok?
5295
        if ic <= lb or ic >= ub:
5296
            exceptionErrorMess =  "Invalid interval center for " + \
5297
                                str(lb) + ',' + str(ic) + ',' +  \
5298
                                str(ub) + ". Aborting!"
5299
            raise Exception(exceptionErrorMess)
5300
        ##### Current interval width and reset future interval width.
5301
        bw = ub - lb
5302
        nbw = 0
5303
        icAsInt = int(ic * toIntegerFactor)
5304
        #### The following ratio is always >= 1. In case we may want to
5305
        #    enlarge the interval
5306
        curTaylErrRat = polyApproxAccur / terr
5307
        ### Make the  integral transformations.
5308
        #### Bounds and interval center.
5309
        intIc = int(ic * toIntegerFactor)
5310
        intLb = int(lb * toIntegerFactor) - intIc
5311
        intUb = int(ub * toIntegerFactor) - intIc
5312
        #
5313
        #### Polynomials
5314
        basisConstructionTime         = cputime()
5315
        ##### To a polynomial with rational coefficients with rational arguments
5316
        ratRatP = slz_float_poly_of_float_to_rat_poly_of_rat_pow_two(floatP)
5317
        if debug:
5318
            print "Polynomial: rational coefficients for rational argument:"
5319
            print ratRatP
5320
        ##### To a polynomial with rational coefficients with integer arguments
5321
        ratIntP = \
5322
            slz_rat_poly_of_rat_to_rat_poly_of_int(ratRatP, precision)
5323
        if debug:
5324
            print "Polynomial: rational coefficients for integer argument:"
5325
            print ratIntP
5326
        #####  Ultimately a multivariate polynomial with integer coefficients  
5327
        #      with integer arguments.
5328
        coppersmithTuple = \
5329
            slz_rat_poly_of_int_to_poly_for_coppersmith(ratIntP, 
5330
                                                        precision, 
5331
                                                        targetHardnessToRound, 
5332
                                                        i, t)
5333
        #### Recover Coppersmith information.
5334
        intIntP = coppersmithTuple[0]
5335
        N = coppersmithTuple[1]
5336
        nAtAlpha = N^alpha
5337
        tBound = coppersmithTuple[2]
5338
        leastCommonMultiple = coppersmithTuple[3]
5339
        iBound = max(abs(intLb),abs(intUb))
5340
        if debug:
5341
            print "Polynomial: integer coefficients for integer argument:"
5342
            print intIntP
5343
            print "N:", N
5344
            print "t bound:", tBound
5345
            print "i bound:", iBound
5346
            print "Least common multiple:", leastCommonMultiple
5347
        basisConstructionsFullTime        += cputime(basisConstructionTime)
5348
        basisConstructionsCount           += 1
5349
        
5350
        #### Compute the matrix to reduce.
5351
        matrixToReduce = slz_compute_initial_lattice_matrix(intIntP,
5352
                                                            alpha,
5353
                                                            N,
5354
                                                            iBound,
5355
                                                            tBound,
5356
                                                            True)
5357
        matrixFile = file('/tmp/matrixToReduce.txt', 'w')
5358
        for row in matrixToReduce.rows():
5359
            matrixFile.write(str(row) + "\n")
5360
        matrixFile.close()
5361
        #raise Exception("Deliberate stop here.")
5362
        
5363
        reductionTime                     = cputime()
5364
        #### Compute the reduced polynomials.
5365
        ccReducedPolynomialsList =  \
5366
                slz_compute_coppersmith_reduced_polynomials_with_lattice_volume(intIntP, 
5367
                                                            alpha, 
5368
                                                            N, 
5369
                                                            iBound, 
5370
                                                            tBound,
5371
                                                            True)
5372
        if ccReducedPolynomialsList is None:
5373
            raise Exception("Reduction failed.")
5374
        reductionsFullTime    += cputime(reductionTime)
5375
        reductionsCount       += 1
5376
        if len(ccReducedPolynomialsList) < 2:
5377
            print "Nothing to form resultants with."
5378
            print
5379
            coppCondFailedCount += 1
5380
            coppCondFailed = True
5381
            ##### Apply a different shrink factor according to 
5382
            #  the number of compliant polynomials.
5383
            if len(ccReducedPolynomialsList) == 0:
5384
                ub = lb + bw * noCoppersmithIntervalShrink
5385
            else: # At least one compliant polynomial.
5386
                ub = lb + bw * oneCoppersmithIntervalShrink
5387
            if ub > sdub:
5388
                ub = sdub
5389
            if lb == ub:
5390
                raise Exception("Cant shrink interval \
5391
                anymore to get Coppersmith condition.")
5392
            nbw = 0
5393
            continue
5394
        #### We have at least two polynomials.
5395
        #    Let us try to compute resultants.
5396
        #    For each resultant computed, go for the solutions.
5397
        ##### Build the pairs list.
5398
        polyPairsList           = []
5399
        for polyOuterIndex in xrange(0, len(ccReducedPolynomialsList) - 1):
5400
            for polyInnerIndex in xrange(polyOuterIndex+1, 
5401
                                         len(ccReducedPolynomialsList)):
5402
                polyPairsList.append((ccReducedPolynomialsList[polyOuterIndex],
5403
                                      ccReducedPolynomialsList[polyInnerIndex]))
5404
        #### Actual root search.
5405
        iRootsSet           = set()
5406
        hasNonNullResultant = False
5407
        for polyPair in polyPairsList:
5408
            resultantsComputationTime   = cputime()
5409
            currentResultantI = \
5410
                slz_resultant(polyPair[0],
5411
                              polyPair[1],
5412
                              t,
5413
                              debug=True)
5414
            resultantsComputationsCount    += 1
5415
            resultantsComputationsFullTime +=  \
5416
                cputime(resultantsComputationTime)
5417
            #### Function slz_resultant returns None both for None and O
5418
            #    resultants.
5419
            if currentResultantI is None:
5420
                print "Nul resultant"
5421
                continue # Next polyPair.
5422
            ## We deleted the currentResultantI computation.
5423
            #### We have a non null resultant. From now on, whatever this
5424
            #    root search yields, no extra root search is necessary.
5425
            hasNonNullResultant = True
5426
            #### A constant resultant leads to no root. Root search is done.
5427
            if currentResultantI.degree() < 1:
5428
                print "Resultant is constant:", currentResultantI
5429
                break # There is no root.
5430
            #### Actual iroots computation.
5431
            rootsComputationTime        = cputime()
5432
            iRootsList = Zi(currentResultantI).roots()
5433
            rootsComputationsCount      +=  1
5434
            rootsComputationsFullTime   =   cputime(rootsComputationTime)
5435
            if len(iRootsList) == 0:
5436
                print "No roots in \"i\"."
5437
                break # No roots in i.
5438
            else:
5439
                for iRoot in iRootsList:
5440
                    # A root is given as a (value, multiplicity) tuple.
5441
                    iRootsSet.add(iRoot[0])
5442
        # End loop for polyPair in polyParsList. We only loop again if a 
5443
        # None or zero resultant is found.
5444
        #### Prepare for results for the current interval..
5445
        intervalResultsList = []
5446
        intervalResultsList.append((lb, ub))
5447
        #### Check roots.
5448
        rootsResultsList = []
5449
        for iRoot in iRootsSet:
5450
            specificRootResultsList = []
5451
            failingBounds           = []
5452
            # Root qualifies for modular equation, test it for hardness to round.
5453
            hardToRoundCaseAsFloat = RRR((icAsInt + iRoot) / toIntegerFactor)
5454
            #print "Before unscaling:", hardToRoundCaseAsFloat.n(prec=precision)
5455
            #print scalingFunction
5456
            scaledHardToRoundCaseAsFloat = \
5457
                scalingFunction(hardToRoundCaseAsFloat) 
5458
            print "Candidate HTRNc at x =", \
5459
                scaledHardToRoundCaseAsFloat.n().str(base=2),
5460
            if slz_is_htrn(scaledHardToRoundCaseAsFloat,
5461
                           function,
5462
                           2^-(targetHardnessToRound),
5463
                           RRR,
5464
                           targetPlusOnePrecRF,
5465
                           quasiExactRF):
5466
                print hardToRoundCaseAsFloat, "is HTRN case."
5467
                specificRootResultsList.append(hardToRoundCaseAsFloat.n().str(base=2))
5468
                if lb <= hardToRoundCaseAsFloat and hardToRoundCaseAsFloat <= ub:
5469
                    print "Found in interval."
5470
                else:
5471
                    print "Found out of interval."
5472
                # Check the i root is within the i bound.
5473
                if abs(iRoot) > iBound:
5474
                    print "IRoot", iRoot, "is out of bounds for modular equation."
5475
                    print "i bound:", iBound
5476
                    failingBounds.append('i')
5477
                    failingBounds.append(iRoot)
5478
                    failingBounds.append(iBound)
5479
                if len(failingBounds) > 0:
5480
                    specificRootResultsList.append(failingBounds)
5481
            else: # From slz_is_htrn...
5482
                print "is not an HTRN case for integer value:", iRoot
5483
            if len(specificRootResultsList) > 0:
5484
                rootsResultsList.append(specificRootResultsList)
5485
        if len(rootsResultsList) > 0:
5486
            intervalResultsList.append(rootsResultsList)
5487
        ### Check if a non null resultant was found. If not shrink the interval.
5488
        if not hasNonNullResultant:
5489
            print "Only null resultants for this reduction, shrinking interval."
5490
            resultCondFailed      =  True
5491
            resultCondFailedCount += 1
5492
            ### Shrink interval for next iteration.
5493
            ub = lb + bw * onlyNullResultantsShrink
5494
            if ub > sdub:
5495
                ub = sdub
5496
            nbw = 0
5497
            continue
5498
        #### An intervalResultsList has at least the bounds.
5499
        globalResultsList.append(intervalResultsList)   
5500
        #### Compute an incremented width for next upper bound, only
5501
        #    if not Coppersmith condition nor resultant condition
5502
        #    failed at the previous run. 
5503
        if not coppCondFailed and not resultCondFailed:
5504
            nbw = noErrorIntervalStretch * bw
5505
        else:
5506
            nbw = bw
5507
        ##### Reset the failure flags. They will be raised
5508
        #     again if needed.
5509
        coppCondFailed   = False
5510
        resultCondFailed = False
5511
        #### For next iteration (at end of loop)
5512
        #print "nbw:", nbw
5513
        lb  = ub
5514
        ub += nbw     
5515
        if ub > sdub:
5516
            ub = sdub
5517
        print
5518
    # End while True
5519
    ## Main loop just ended.
5520
    globalWallTime = walltime(wallTimeStart)
5521
    globalCpuTime  = cputime(cpuTimeStart)
5522
    ## Output results
5523
    print ; print "Intervals and HTRNs" ; print
5524
    for intervalResultsList in globalResultsList:
5525
        intervalResultString = "[" + str(intervalResultsList[0][0]) +\
5526
                               "," + str(intervalResultsList[0][1])  + "]"
5527
        print intervalResultString,
5528
        if len(intervalResultsList) > 1:
5529
            rootsResultsList = intervalResultsList[1]
5530
            specificRootResultIndex = 0
5531
            for specificRootResultsList in rootsResultsList:
5532
                if specificRootResultIndex == 0:
5533
                    print "\t", specificRootResultsList[0],
5534
                else:
5535
                    print " " * len(intervalResultString), "\t", \
5536
                          specificRootResultsList[0],
5537
                if len(specificRootResultsList) > 1:
5538
                    print specificRootResultsList[1]
5539
                specificRootResultIndex += 1
5540
        print ; print
5541
    #print globalResultsList
5542
    #
5543
    print "Timers and counters"
5544
    print
5545
    print "Number of iterations:", iterCount
5546
    print "Taylor condition failures:", taylCondFailedCount
5547
    print "Coppersmith condition failures:", coppCondFailedCount
5548
    print "Resultant condition failures:", resultCondFailedCount
5549
    print "Iterations count: ", iterCount
5550
    print "Number of intervals:", len(globalResultsList)
5551
    print "Number of basis constructions:", basisConstructionsCount 
5552
    print "Total CPU time spent in basis constructions:", \
5553
        basisConstructionsFullTime
5554
    if basisConstructionsCount != 0:
5555
        print "Average basis construction CPU time:", \
5556
            basisConstructionsFullTime/basisConstructionsCount
5557
    print "Number of reductions:", reductionsCount
5558
    print "Total CPU time spent in reductions:", reductionsFullTime
5559
    if reductionsCount != 0:
5560
        print "Average reduction CPU time:", \
5561
            reductionsFullTime/reductionsCount
5562
    print "Number of resultants computation rounds:", \
5563
        resultantsComputationsCount
5564
    print "Total CPU time spent in resultants computation rounds:", \
5565
        resultantsComputationsFullTime
5566
    if resultantsComputationsCount != 0:
5567
        print "Average resultants computation round CPU time:", \
5568
            resultantsComputationsFullTime/resultantsComputationsCount
5569
    print "Number of root finding rounds:", rootsComputationsCount
5570
    print "Total CPU time spent in roots finding rounds:", \
5571
        rootsComputationsFullTime
5572
    if rootsComputationsCount != 0:
5573
        print "Average roots finding round CPU time:", \
5574
            rootsComputationsFullTime/rootsComputationsCount
5575
    print "Global Wall time:", globalWallTime
5576
    print "Global CPU time:", globalCpuTime
5577
    ## Output counters
5578
# End srs_runSLZ-v06
5579
sys.stderr.write("\t...sage Runtime SLZ loaded.\n")