Statistiques
| Révision :

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

Historique | Voir | Annoter | Télécharger (42,4 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