Ticket #723: ntls-fp-lll.patch

File ntls-fp-lll.patch, 18.2 KB (added by malb, 2 years ago)
  • sage/libs/ntl/ntl_mat_ZZ.pyx

    # HG changeset patch
    # User Martin Albrecht <malb@informatik.uni-bremen.de>
    # Date 1190417056 -3600
    # Node ID 2bb5a85fe302ae44f6147b176ef3f45e987d2fbd
    # Parent  5f0e731bb66c2c4ad46d97bdfab24a55c689d43e
    NTL's floating point LLL exposed
    
    diff -r 5f0e731bb66c -r 2bb5a85fe302 sage/libs/ntl/ntl_mat_ZZ.pyx
    a b  
    1717include "../../ext/stdsage.pxi" 
    1818include 'misc.pxi' 
    1919include 'decl.pxi' 
     20 
     21cdef extern from "NTL/LLL.h": 
     22    cdef long mat_ZZ_LLL_FP   "LLL_FP"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     23    cdef long mat_ZZ_LLL_FP_U "LLL_FP"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     24    cdef long mat_ZZ_LLL_QP   "LLL_QP"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     25    cdef long mat_ZZ_LLL_QP_U "LLL_QP"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     26    cdef long mat_ZZ_LLL_XD   "LLL_XD"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     27    cdef long mat_ZZ_LLL_XD_U "LLL_XD"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     28    cdef long mat_ZZ_LLL_RR   "LLL_RR"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     29    cdef long mat_ZZ_LLL_RR_U "LLL_RR"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     30 
     31    cdef long mat_ZZ_G_LLL_FP   "G_LLL_FP"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     32    cdef long mat_ZZ_G_LLL_FP_U "G_LLL_FP"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     33    cdef long mat_ZZ_G_LLL_QP   "G_LLL_QP"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     34    cdef long mat_ZZ_G_LLL_QP_U "G_LLL_QP"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     35    cdef long mat_ZZ_G_LLL_XD   "G_LLL_XD"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     36    cdef long mat_ZZ_G_LLL_XD_U "G_LLL_XD"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     37    cdef long mat_ZZ_G_LLL_RR   "G_LLL_RR"(mat_ZZ_c B, double delta, int deep, int check , int verbose) 
     38    cdef long mat_ZZ_G_LLL_RR_U "G_LLL_RR"(mat_ZZ_c B, mat_ZZ_c U, double delta, int deep, int check , int verbose) 
     39 
    2040 
    2141from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ 
    2242from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX 
     
    352372            rank = int(mat_ZZ_LLL(&det2,&self.x,int(a),int(b),int(verbose))) 
    353373            _sig_off 
    354374            return rank,make_ZZ(det2) 
     375 
     376    def LLL_FP(self, delta=0.75 , return_U=False, verbose=False): 
     377        r""" 
     378        Performs approximate LLL reduction of self (puts self in an 
     379        LLL form) subject to the following conditions: 
     380 
     381        The precision is double. 
     382         
     383        The return value is the rank of B. 
     384 
     385        Classical Gramm-Schmidt Orthogonalization is used: 
     386 
     387        This choice uses classical methods for computing the 
     388        Gramm-Schmidt othogonalization.  It is fast but prone to 
     389        stability problems.  This strategy was first proposed by 
     390        Schnorr and Euchner [C. P. Schnorr and M. Euchner, 
     391        Proc. Fundamentals of Computation Theory, LNCS 529, pp. 68-85, 
     392        1991].  The version implemented here is substantially 
     393        different, improving both stability and performance. 
     394         
     395        If return_U is True, then also U is returned which is 
     396        the transition matrix: $U * self_{old} = self_{new}$ 
     397 
     398        The optional argument 'delta' is the reduction parameter, and 
     399        may be set so that 0.50 <= delta < 1.  Setting it close to 1 
     400        yields shorter vectors, and also improves the stability, but 
     401        increases the running time.  Recommended value: delta = 
     402        0.99. 
     403 
     404        The optional parameter 'verbose' can be set to see all kinds 
     405        of fun things printed while the routine is executing.  A 
     406        status report is also printed every once in a while. 
     407 
     408        INPUT: 
     409           delta    -- as described above (0.5 <= delta < 1.0) (default: 0.75) 
     410           return_U -- return U as described above 
     411           verbose  -- if True NTL will produce some verbatim messages on 
     412                       what's going on internally (default: False) 
     413 
     414        OUTPUT: 
     415            (rank,[U]) where rank and U are as described above and U 
     416            is an optional return value if return_U is True. 
     417 
     418        EXAMPLE: 
     419            sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) 
     420            sage: M.LLL_FP() 
     421            2 
     422            sage: M 
     423            [[0 0 0] 
     424            [2 1 0] 
     425            [-1 1 3] 
     426            ] 
     427            sage: M=ntl.mat_ZZ(4,4,[-6,9,-15,-18,4,-6,10,12,10,-16,18,35,-24,36,-46,-82]); M 
     428            [[-6 9 -15 -18] 
     429            [4 -6 10 12] 
     430            [10 -16 18 35] 
     431            [-24 36 -46 -82] 
     432            ] 
     433            sage: M.LLL_FP() 
     434            3 
     435            sage: M 
     436            [[0 0 0 0] 
     437            [0 -2 0 0] 
     438            [-2 1 -5 -6] 
     439            [0 -1 -7 5] 
     440            ] 
     441 
     442        WARNING: This method modifies self. So after applying this method your matrix 
     443        will be a vector of vectors. 
     444        """ 
     445        cdef ntl_mat_ZZ U 
     446        if return_U: 
     447            U = PY_NEW(ntl_mat_ZZ) 
     448            _sig_on 
     449            rank = int(mat_ZZ_LLL_FP_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     450            _sig_off 
     451            return rank, U 
     452        else: 
     453            _sig_on 
     454            rank = int(mat_ZZ_LLL_FP(self.x,float(delta),0,0,int(verbose))) 
     455            _sig_off 
     456            return rank 
     457 
     458    def LLL_QP(self, delta, return_U=False, verbose=False): 
     459        r""" 
     460        Peforms the same reduction as self.LLL_FP using the same 
     461        calling conventions but with quad float precision. 
     462        """ 
     463        cdef ntl_mat_ZZ U 
     464        if return_U: 
     465            U = PY_NEW(ntl_mat_ZZ) 
     466            _sig_on 
     467            rank = int(mat_ZZ_LLL_QP_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     468            _sig_off 
     469            return rank, U 
     470        else: 
     471            _sig_on 
     472            rank = int(mat_ZZ_LLL_QP(self.x,float(delta),0,0,int(verbose))) 
     473            _sig_off 
     474            return rank 
     475 
     476    def LLL_XD(self, delta, return_U=False, verbose=False): 
     477        r""" 
     478        Peforms the same reduction as self.LLL_FP using the same 
     479        calling conventions but with extended exponent double 
     480        precision. 
     481        """ 
     482        cdef ntl_mat_ZZ U 
     483        if return_U: 
     484            U = PY_NEW(ntl_mat_ZZ) 
     485            _sig_on 
     486            rank = int(mat_ZZ_LLL_XD_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     487            _sig_off 
     488            return rank, U 
     489        else: 
     490            _sig_on 
     491            rank = int(mat_ZZ_LLL_XD(self.x,float(delta),0,0,int(verbose))) 
     492            _sig_off 
     493            return rank 
     494 
     495    def LLL_RR(self, delta, return_U=False, verbose=False): 
     496        r""" 
     497        Peforms the same reduction as self.LLL_FP using the same 
     498        calling conventions but with arbitrary precision floating 
     499        point numbers. 
     500        """ 
     501        cdef ntl_mat_ZZ U 
     502        if return_U: 
     503            U = PY_NEW(ntl_mat_ZZ) 
     504            _sig_on 
     505            rank = int(mat_ZZ_LLL_RR_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     506            _sig_off 
     507            return rank, U 
     508        else: 
     509            _sig_on 
     510            rank = int(mat_ZZ_LLL_RR(self.x,float(delta),0,0,int(verbose))) 
     511            _sig_off 
     512            return rank 
     513 
     514    # Givens Orthogonalization.  This is a bit slower, but generally 
     515    # much more stable, and is really the preferred orthogonalization 
     516    # strategy.  For a nice description of this, see Chapter 5 of 
     517    # [G. Golub and C. van Loan, Matrix Computations, 3rd edition, 
     518    # Johns Hopkins Univ. Press, 1996]. 
     519 
     520    def G_LLL_FP(self, delta, return_U=False, verbose=False): 
     521        r""" 
     522        Peforms the same reduction as self.LLL_FP using the same 
     523        calling conventions but uses the Givens Orthogonalization. 
     524 
     525        Givens Orthogonalization.  This is a bit slower, but generally 
     526        much more stable, and is really the preferred 
     527        orthogonalization strategy.  For a nice description of this, 
     528        see Chapter 5 of [G. Golub and C. van Loan, Matrix 
     529        Computations, 3rd edition, Johns Hopkins Univ. Press, 1996]. 
     530        """ 
     531        cdef ntl_mat_ZZ U 
     532        if return_U: 
     533            U = PY_NEW(ntl_mat_ZZ) 
     534            _sig_on 
     535            rank = int(mat_ZZ_G_LLL_FP_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     536            _sig_off 
     537            return rank, U 
     538        else: 
     539            _sig_on 
     540            rank = int(mat_ZZ_G_LLL_FP(self.x,float(delta),0,0,int(verbose))) 
     541            _sig_off 
     542            return rank 
     543 
     544    def G_LLL_QP(self, delta, return_U=False, verbose=False): 
     545        r""" 
     546        Peforms the same reduction as self.G_LLL_FP using the same 
     547        calling conventions but with quad float precision. 
     548        """ 
     549        cdef ntl_mat_ZZ U 
     550        if return_U: 
     551            U = PY_NEW(ntl_mat_ZZ) 
     552            _sig_on 
     553            rank = int(mat_ZZ_G_LLL_QP_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     554            _sig_off 
     555            return rank, U 
     556        else: 
     557            _sig_on 
     558            rank = int(mat_ZZ_G_LLL_QP(self.x,float(delta),0,0,int(verbose))) 
     559            _sig_off 
     560            return rank 
     561 
     562    def G_LLL_XD(self, delta, return_U=False, verbose=False): 
     563        r""" 
     564        Peforms the same reduction as self.G_LLL_FP using the same 
     565        calling conventions but with extended exponent double 
     566        precision. 
     567        """ 
     568        cdef ntl_mat_ZZ U 
     569        if return_U: 
     570            U = PY_NEW(ntl_mat_ZZ) 
     571            _sig_on 
     572            rank = int(mat_ZZ_G_LLL_XD_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     573            _sig_off 
     574            return rank, U 
     575        else: 
     576            _sig_on 
     577            rank = int(mat_ZZ_G_LLL_XD(self.x,float(delta),0,0,int(verbose))) 
     578            _sig_off 
     579            return rank 
     580 
     581    def G_LLL_RR(self, delta, return_U=False, verbose=False): 
     582        r""" 
     583        Peforms the same reduction as self.G_LLL_FP using the same 
     584        calling conventions but with aribitrary precision floating 
     585        point numbers. 
     586        """ 
     587        cdef ntl_mat_ZZ U 
     588        if return_U: 
     589            U = PY_NEW(ntl_mat_ZZ) 
     590            _sig_on 
     591            rank = int(mat_ZZ_G_LLL_RR_U(self.x, U.x, float(delta), 0, 0, int(verbose))) 
     592            _sig_off 
     593            return rank, U 
     594        else: 
     595            _sig_on 
     596            rank = int(mat_ZZ_G_LLL_RR(self.x,float(delta),0,0,int(verbose))) 
     597            _sig_off 
     598            return rank 
  • sage/matrix/matrix_integer_dense.pyx

    diff -r 5f0e731bb66c -r 2bb5a85fe302 sage/matrix/matrix_integer_dense.pyx
    a b  
    14041404    #################################################################################### 
    14051405    # LLL 
    14061406    ####################################################################################     
    1407     def lllgram(self): 
     1407    def LLL_gram(self): 
    14081408        """ 
    14091409        LLL reduction of the lattice whose gram matrix is self. 
    14101410 
     
    14251425            sage: M = Matrix(ZZ, 2, 2, [5,3,3,2]) ; M 
    14261426            [5 3] 
    14271427            [3 2] 
    1428             sage: U = M.lllgram(); U 
     1428            sage: U = M.LLL_gram(); U 
    14291429            [-1  1] 
    14301430            [ 1 -2] 
    14311431            sage: U.transpose() * M * U 
     
    14341434             
    14351435        Semidefinite and indefinite forms raise a ValueError: 
    14361436 
    1437             sage: Matrix(ZZ,2,2,[2,6,6,3]).lllgram() 
     1437            sage: Matrix(ZZ,2,2,[2,6,6,3]).LLL_gram() 
    14381438            Traceback (most recent call last): 
    14391439            ... 
    14401440            ValueError: not a definite matrix 
    1441             sage: Matrix(ZZ,2,2,[1,0,0,-1]).lllgram() 
     1441            sage: Matrix(ZZ,2,2,[1,0,0,-1]).LLL_gram() 
    14421442            Traceback (most recent call last): 
    14431443            ... 
    14441444            ValueError: not a definite matrix 
     
    14641464                U[i,n-1] = - U[i,n-1] 
    14651465        return U 
    14661466 
    1467     def lll(self, delta=None): 
     1467    def LLL(self, delta=None, algorithm=None, **kwargs): 
    14681468        r""" 
    1469         Returns LLL reduced lattice R for self. 
     1469        Returns LLL reduced or approximated LLL reduced lattice R for 
     1470        self. 
    14701471 
    14711472        The lattice is returned as a matrix. Also the rank (and the 
    14721473        determinant) of self are cached. 
    14731474 
    14741475        More specifically, elementary row transformations are 
    1475         performed on a copy of self so that the non-zero rows of 
    1476         R form an LLL-reduced basis for the lattice spanned by 
    1477         the rows of self. The default reduction parameter is 
    1478         $\delta=3/4$, which means that the squared length of the first 
    1479         non-zero basis vector is no more than $2^{r-1}$ times that of 
    1480         the shortest vector in the lattice. 
     1476        performed on a copy of self so that the non-zero rows of R 
     1477        form an LLL-reduced basis for the lattice spanned by the rows 
     1478        of self. The default reduction parameter is $\delta=3/4$, 
     1479        which means that the squared length of the first non-zero 
     1480        basis vector is no more than $2^{r-1}$ times that of the 
     1481        shortest vector in the lattice. 
    14811482 
    14821483        For a basis reduced with parameter $\delta$, the squared 
    14831484        length of the first non-zero basis vector is no more than 
     
    14861487 
    14871488        If we can compute the determinant of self using this method, 
    14881489        we also cache it. Note that in general this only happens when 
    1489         self.rank() == self.ncols(). 
     1490        self.rank() == self.ncols() and the exact algorithm is used. 
    14901491 
    14911492        INPUT: 
    1492            delta -- arameter a as described above (default: 3/4) 
     1493            delta -- arameter a as described above (default: 3/4) 
     1494            algorithm -- string, one of the algorithms mentioned above 
     1495                        or None (default: None) 
     1496            use_givens -- use Givens orthogonalization (default: False) 
     1497                          only applicable to approximate reductions and NTL. 
     1498                          This is more stable but slower. 
     1499 
     1500        Also, if the verbose level is >= 2, some more verbose output 
     1501        is printed during the calculation if NTL is used. 
     1502 
     1503        AVAILABLE ALGORITHMS: 
     1504            NTL:LLL -- default, exact reduction 
     1505            NTL:LLL_FP -- approximate reduction over double precision 
     1506                          floating point numbers. 
     1507            NTL:LLL_QP -- approximate reduction over quad precision 
     1508                          floating point numbers. 
     1509            NTL:LLL_XD -- approximate reduction over extended exponent 
     1510                          double precision floating point numbers. 
     1511            NTL:LLL_RR -- approximate reduction over arbitrary precision 
     1512                          floating point numbers. 
    14931513 
    14941514        OUTPUT: 
    14951515            a matrix over the integers 
    14961516 
    14971517        EXAMPLE: 
    14981518            sage: A = Matrix(ZZ,3,3,range(1,10)) 
    1499             sage: A.lll() 
     1519            sage: A.LLL() 
    15001520            [ 0  0  0] 
    15011521            [ 2  1  0] 
    15021522            [-1  1  3] 
    15031523             
    15041524        ALGORITHM: Uses NTL. 
     1525 
     1526        REFERENCES: 
     1527            ntl.mat_ZZ for details on the used algorithms. 
    15051528        """ 
    15061529 
    15071530        import sage.libs.ntl.all 
    15081531        ntl_ZZ = sage.libs.ntl.all.ZZ 
    15091532 
    1510         if delta is None: 
    1511             delta = ZZ(3)/ZZ(4) 
    1512         elif delta <= ZZ(1)/ZZ(4): 
    1513             raise TypeError, "delta must be > 1/4" 
    1514         elif delta > 1: 
    1515             raise TypeError, "delta must be <= 1/4" 
    1516  
    1517         delta = delta/ZZ(1) # QQ(delta) 
    1518  
    1519         a = delta.numer() 
    1520         b = delta.denom() 
     1533        if get_verbose() >= 2: verb = True 
     1534        else: verb = False 
     1535 
     1536        use_givens = kwargs.get("use_givens",False) 
     1537 
     1538        if algorithm is None: 
     1539            algorithm = "NTL:LLL" 
     1540 
     1541        if algorithm == "NTL:LLL": 
     1542            if delta is None: 
     1543                delta = ZZ(3)/ZZ(4) 
     1544            elif delta <= ZZ(1)/ZZ(4): 
     1545                raise TypeError, "delta must be > 1/4" 
     1546            elif delta > 1: 
     1547                raise TypeError, "delta must be <= 1" 
     1548 
     1549            delta = QQ(delta) # QQ(delta) 
     1550            a = delta.numer() 
     1551            b = delta.denom() 
     1552 
     1553        elif algorithm in ("NTL:LLL_FP","NTL:LLL_QP","NTL:LLL_XD","NTL:LLL_RR"): 
     1554            if delta is None: 
     1555                delta = 0.99 
     1556            elif delta < 0.5: 
     1557                raise TypeError, "delta must be >= 0.5" 
     1558            elif delta > 1: 
     1559                raise TypeError, "delta must be <= 1" 
     1560            delta = float(delta) 
    15211561 
    15221562        A = sage.libs.ntl.all.mat_ZZ(self.nrows(),self.ncols(),map(ntl_ZZ,self.list())) 
    1523         r, det2 = A.LLL(a,b) 
    1524         r,det2 = ZZ(r), ZZ(det2) 
     1563 
     1564        if algorithm == "NTL:LLL": 
     1565            r, det2 = A.LLL(a,b, verbose=verb) 
     1566            det2 = ZZ(det2) 
     1567            try: 
     1568                det = ZZ(det2.sqrt_approx()) 
     1569                self.cache("det", det) 
     1570            except TypeError: 
     1571                pass 
     1572        elif algorithm == "NTL:LLL_FP": 
     1573            if use_givens: 
     1574                r = A.G_LLL_FP(delta, verbose=verb) 
     1575            else: 
     1576                r = A.LLL_FP(delta, verbose=verb) 
     1577        elif algorithm == "NTL:LLL_QP": 
     1578            if use_givens: 
     1579                r = A.G_LLL_QP(delta, verbose=verb) 
     1580            else: 
     1581                r = A.LLL_QP(delta, verbose=verb) 
     1582        elif algorithm == "NTL:LLL_XD": 
     1583            if use_givens: 
     1584                r = A.G_LLL_XD(delta, verbose=verb) 
     1585            else: 
     1586                r = A.LLL_XD(delta, verbose=verb) 
     1587        elif algorithm == "NTL:LLL_RR": 
     1588            if use_givens: 
     1589                r = A.G_LLL_RR(delta, verbose=verb) 
     1590            else: 
     1591                r = A.LLL_XD(delta, verbose=verb) 
     1592        else: 
     1593            raise TypeError, "algorithm %s not supported"%algorithm 
     1594 
     1595        r = ZZ(r) 
    15251596 
    15261597        cdef Matrix_integer_dense R = <Matrix_integer_dense>self.new_matrix(entries=map(ZZ,A.list())) 
    15271598        self.cache("rank",r) 
    1528         try: 
    1529             det = ZZ(det2.sqrt_approx()) 
    1530             self.cache("det", det) 
    1531         except TypeError: 
    1532             pass 
     1599 
    15331600        return R 
    15341601 
    15351602    def prod_of_row_sums(self, cols):