Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (86,9 ko)

1
"""
2
SLZ runtime function.
3
"""
4

    
5
def srs_run_SLZ_v01(inputFunction,
6
                    inputLowerBound,
7
                    inputUpperBound,
8
                    alpha,
9
                    degree,
10
                    precision,
11
                    emin,
12
                    emax,
13
                    targetHardnessToRound,
14
                    debug = False):
15

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

    
465
def srs_run_SLZ_v02(inputFunction,
466
                    inputLowerBound,
467
                    inputUpperBound,
468
                    alpha,
469
                    degree,
470
                    precision,
471
                    emin,
472
                    emax,
473
                    targetHardnessToRound,
474
                    debug = False):
475
    """
476
    Changes from V1: 
477
        1- check for roots as soon as a resultant is computed;
478
        2- once a non null resultant is found, check for roots;
479
        3- constant resultant == no root.
480
    """
481

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

    
940
def srs_run_SLZ_v03(inputFunction,
941
                    inputLowerBound,
942
                    inputUpperBound,
943
                    alpha,
944
                    degree,
945
                    precision,
946
                    emin,
947
                    emax,
948
                    targetHardnessToRound,
949
                    debug = False):
950
    """
951
    Changes from V2:
952
        Root search is changed:
953
            - we compute the resultants in i and in t;
954
            - we compute the roots set of each of these resultants;
955
            - we combine all the possible pairs between the two sets;
956
            - we check these pairs in polynomials for correctness.
957
    Changes from V1: 
958
        1- check for roots as soon as a resultant is computed;
959
        2- once a non null resultant is found, check for roots;
960
        3- constant resultant == no root.
961
    """
962

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

    
1434
def srs_compute_lattice_volume(inputFunction,
1435
                    inputLowerBound,
1436
                    inputUpperBound,
1437
                    alpha,
1438
                    degree,
1439
                    precision,
1440
                    emin,
1441
                    emax,
1442
                    targetHardnessToRound,
1443
                    debug = False):
1444
    """
1445
    Changes from V2:
1446
        Root search is changed:
1447
            - we compute the resultants in i and in t;
1448
            - we compute the roots set of each of these resultants;
1449
            - we combine all the possible pairs between the two sets;
1450
            - we check these pairs in polynomials for correctness.
1451
    Changes from V1: 
1452
        1- check for roots as soon as a resultant is computed;
1453
        2- once a non null resultant is found, check for roots;
1454
        3- constant resultant == no root.
1455
    """
1456

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