Statistiques
| Révision :

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

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

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

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