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

sageRunSLZ.sage (revision 219)
1950 1950
    Changes from V3:
1951 1951
        Root search is changed again:
1952 1952
            - only resultants in i are computed;
1953
            - root are searched for;
1953
            - roots in i are searched for;
1954 1954
            - if any, they are tested for hardness-to-round.
1955 1955
    Changes from V2:
1956 1956
        Root search is changed:
......
2396 2396
    ## Output counters
2397 2397
# End srs_runSLZ-v04
2398 2398

  
2399
def srs_run_SLZ_v05(inputFunction,
2400
                    inputLowerBound,
2401
                    inputUpperBound,
2402
                    alpha,
2403
                    degree,
2404
                    precision,
2405
                    emin,
2406
                    emax,
2407
                    targetHardnessToRound,
2408
                    debug = False):
2409
    """
2410
    Changes from V4:
2411
        Approximation polynomial has coefficients rounded.
2412
    Changes from V3:
2413
        Root search is changed again:
2414
            - only resultants in i are computed;
2415
            - roots in i are searched for;
2416
            - if any, they are tested for hardness-to-round.
2417
    Changes from V2:
2418
        Root search is changed:
2419
            - we compute the resultants in i and in t;
2420
            - we compute the roots set of each of these resultants;
2421
            - we combine all the possible pairs between the two sets;
2422
            - we check these pairs in polynomials for correctness.
2423
    Changes from V1: 
2424
        1- check for roots as soon as a resultant is computed;
2425
        2- once a non null resultant is found, check for roots;
2426
        3- constant resultant == no root.
2427
    """
2428

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

Formats disponibles : Unified diff