Révision 244 pobysoPythonSage/src/sageSLZ/sageRunSLZ.sage

sageRunSLZ.sage (revision 244)
2951 2951
    print "Global CPU time:", globalCpuTime
2952 2952
    ## Output counters
2953 2953
# End srs_runSLZ-v05
2954
#
2955
def srs_run_SLZ_v05_gram(inputFunction,
2956
                         inputLowerBound,
2957
                         inputUpperBound,
2958
                         alpha,
2959
                         degree,
2960
                         precision,
2961
                         emin,
2962
                         emax,
2963
                         targetHardnessToRound,
2964
                         debug = False):
2965
    """
2966
    changes from plain V5:
2967
        Uses Pari LLL reduction from the Gram matrix.
2968
    Changes from V4:
2969
        Approximation polynomial has coefficients rounded.
2970
    Changes from V3:
2971
        Root search is changed again:
2972
            - only resultants in i are computed;
2973
            - roots in i are searched for;
2974
            - if any, they are tested for hardness-to-round.
2975
    Changes from V2:
2976
        Root search is changed:
2977
            - we compute the resultants in i and in t;
2978
            - we compute the roots set of each of these resultants;
2979
            - we combine all the possible pairs between the two sets;
2980
            - we check these pairs in polynomials for correctness.
2981
    Changes from V1: 
2982
        1- check for roots as soon as a resultant is computed;
2983
        2- once a non null resultant is found, check for roots;
2984
        3- constant resultant == no root.
2985
    """
2954 2986

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

Formats disponibles : Unified diff