| 477 | | cdef _init_linbox(self): |
| 478 | | _sig_on |
| 479 | | linbox.set(self.p, self._nrows, self._ncols, self.rows) |
| 480 | | _sig_off |
| 481 | | |
| 482 | | def _rank_linbox(self): |
| 483 | | """ |
| 484 | | See self.rank(). |
| 485 | | """ |
| 486 | | if is_prime(self.p): |
| 487 | | x = self.fetch('rank') |
| 488 | | if not x is None: |
| 489 | | return x |
| 490 | | self._init_linbox() |
| 491 | | _sig_on |
| 492 | | # the returend pivots list is currently wrong |
| 493 | | #r, pivots = linbox.rank(1) |
| 494 | | r = linbox.rank(1) |
| 495 | | r = Integer(r) |
| 496 | | _sig_off |
| 497 | | self.cache('rank', r) |
| 498 | | return r |
| 499 | | else: |
| 500 | | raise TypeError, "only GF(p) supported via LinBox" |
| 501 | | |
| 502 | | def rank(self, gauss=False): |
| 503 | | """ |
| 504 | | Compute the rank of self. |
| 505 | | |
| 506 | | INPUT: |
| 507 | | gauss -- if True Gaussian elimination is used. If False |
| 508 | | 'Symbolic Reordering' as implemented in LinBox |
| 509 | | is used. (default: False) |
| 510 | | |
| 511 | | EXAMPLE: |
| 512 | | sage: A = random_matrix(GF(127),200,200,density=0.01,sparse=True) |
| 513 | | sage: r1 = A.rank(gauss=False) |
| 514 | | sage: r2 = A.rank(gauss=True) |
| 515 | | sage: r1 == r2 |
| 516 | | True |
| 517 | | |
| 518 | | ALGORITHM: Uses LinBox or native implementation. |
| 519 | | |
| 520 | | REFERENCES: Jean-Guillaume Dumas and Gilles Villars. 'Computing the |
| 521 | | Rank of Large Sparse Matrices over Finite Fields'. Proc. CASC'2002, |
| 522 | | The Fifth International Workshop on Computer Algebra in Scientific Computing, |
| 523 | | Big Yalta, Crimea, Ukraine, 22-27 sept. 2002, Springer-Verlag, |
| 524 | | http://perso.ens-lyon.fr/gilles.villard/BIBLIOGRAPHIE/POSTSCRIPT/rankjgd.ps |
| 525 | | |
| 526 | | NOTE: |
| 527 | | For very sparse matrices Gaussian elimination is faster because |
| 528 | | it barly has anything to do. If the fill in needs to be considered, |
| 529 | | 'Symbolic Reordering' is usually much faster. |
| 530 | | """ |
| 531 | | x = self.fetch('rank') |
| 532 | | if not x is None: return x |
| 533 | | |
| 534 | | if is_prime(self.p) and not gauss: |
| 535 | | return self._rank_linbox() |
| 536 | | else: |
| 537 | | return Matrix0.rank(self) |
| 538 | | |
| 640 | | ## def _solve(self, Matrix_modn_sparse B): |
| 641 | | ## """ |
| 642 | | ## """ |
| 643 | | ## cdef c_vector_modint *X |
| 644 | | |
| 645 | | ## cdef Matrix_modn_sparse C |
| 646 | | |
| 647 | | ## if not self.is_square(): |
| 648 | | ## raise NotImplementedError, "input matrix must be square" |
| 649 | | |
| 650 | | ## if self.rank() != self.nrows(): |
| 651 | | ## raise ValueError, "input matrix must have full rank but it doesn't" |
| 652 | | |
| 653 | | ## self._init_linbox() |
| 654 | | |
| 655 | | ## matrix = True |
| 656 | | ## if is_Vector(B): |
| 657 | | ## matrix = False |
| 658 | | ## C = self.matrix_space(1,self.nrows())(B.list()) |
| 659 | | |
| 660 | | ## #_sig_on |
| 661 | | ## linbox.solve(&X, C.rows) |
| 662 | | ## #_sig_off |
| 663 | | |
| 664 | | ## ## X = None |
| 665 | | ## ## if not matrix: |
| 666 | | ## ## # Convert back to a vector |
| 667 | | ## ## return (X.base_ring() ** X.nrows())(X.list()) |
| 668 | | ## ## else: |
| 669 | | ## ## return X |
| | 578 | cdef _init_linbox(self): |
| | 579 | _sig_on |
| | 580 | linbox.set(self.p, self._nrows, self._ncols, self.rows) |
| | 581 | _sig_off |
| | 582 | |
| | 583 | def _rank_linbox(self, method): |
| | 584 | """ |
| | 585 | See self.rank(). |
| | 586 | """ |
| | 587 | if is_prime(self.p): |
| | 588 | x = self.fetch('rank') |
| | 589 | if not x is None: |
| | 590 | return x |
| | 591 | self._init_linbox() |
| | 592 | _sig_on |
| | 593 | # the returend pivots list is currently wrong |
| | 594 | #r, pivots = linbox.rank(1) |
| | 595 | r = linbox.rank(method) |
| | 596 | r = Integer(r) |
| | 597 | _sig_off |
| | 598 | self.cache('rank', r) |
| | 599 | return r |
| | 600 | else: |
| | 601 | raise TypeError, "only GF(p) supported via LinBox" |
| | 602 | |
| | 603 | def rank(self, gauss=False): |
| | 604 | """ |
| | 605 | Compute the rank of self. |
| | 606 | |
| | 607 | INPUT: |
| | 608 | gauss -- if True LinBox' Gaussian elimination is used. If False |
| | 609 | 'Symbolic Reordering' as implemented in LinBox |
| | 610 | is used. If 'native' the native SAGE implementation |
| | 611 | is used. (default: False) |
| | 612 | |
| | 613 | EXAMPLE: |
| | 614 | sage: A = random_matrix(GF(127),200,200,density=0.01,sparse=True) |
| | 615 | sage: r1 = A.rank(gauss=False) |
| | 616 | sage: r2 = A.rank(gauss=True) |
| | 617 | sage: r3 = A.rank(gauss='native') |
| | 618 | sage: r1 == r2 == r3 |
| | 619 | True |
| | 620 | |
| | 621 | ALGORITHM: Uses LinBox or native implementation. |
| | 622 | |
| | 623 | REFERENCES: Jean-Guillaume Dumas and Gilles Villars. 'Computing the |
| | 624 | Rank of Large Sparse Matrices over Finite Fields'. Proc. CASC'2002, |
| | 625 | The Fifth International Workshop on Computer Algebra in Scientific Computing, |
| | 626 | Big Yalta, Crimea, Ukraine, 22-27 sept. 2002, Springer-Verlag, |
| | 627 | http://perso.ens-lyon.fr/gilles.villard/BIBLIOGRAPHIE/POSTSCRIPT/rankjgd.ps |
| | 628 | |
| | 629 | NOTE: |
| | 630 | For very sparse matrices Gaussian elimination is faster because |
| | 631 | it barly has anything to do. If the fill in needs to be considered, |
| | 632 | 'Symbolic Reordering' is usually much faster. |
| | 633 | """ |
| | 634 | x = self.fetch('rank') |
| | 635 | if not x is None: return x |
| | 636 | |
| | 637 | if is_prime(self.p): |
| | 638 | if gauss is False: |
| | 639 | return self._rank_linbox(0) |
| | 640 | elif gauss is True: |
| | 641 | return self._rank_linbox(1) |
| | 642 | elif gauss == "native": |
| | 643 | return Matrix2.rank(self) |
| | 644 | else: |
| | 645 | raise TypeError, "parameter 'gauss' not understood" |
| | 646 | else: |
| | 647 | return Matrix2.rank(self) |
| | 648 | |
| | 649 | def solve_right(self, B, algorithm=None, check_rank = True): |
| | 650 | """ |
| | 651 | If self is a matrix $A$, then this function returns a vector |
| | 652 | or matrix $X$ such that $A X = B$. If $B$ is a vector then |
| | 653 | $X$ is a vector and if $B$ is a matrix, then $X$ is a matrix. |
| | 654 | |
| | 655 | NOTE: In SAGE one can also write \code{A \ B} for |
| | 656 | \code{A.solve_right(B)}, i.e., SAGE implements the ``the |
| | 657 | MATLAB/Octave backslash operator''. |
| | 658 | |
| | 659 | INPUT: |
| | 660 | B -- a matrix or vector |
| | 661 | algorithm -- one of the following: |
| | 662 | 'LinBox:BlasElimination' -- dense elimination |
| | 663 | 'LinBox:Blackbox' -- LinBox chooses a Blackbox algorithm |
| | 664 | 'LinBox:Wiedemann' -- Wiedemann's algorithm |
| | 665 | 'generic' -- use generic implementation (inversion) |
| | 666 | None -- LinBox chooses an algorithm (default) |
| | 667 | check_rank -- check rank before attempting to solve (default: True) |
| | 668 | |
| | 669 | OUTPUT: |
| | 670 | a matrix or vector |
| | 671 | |
| | 672 | EXAMPLES: |
| | 673 | sage: A = matrix(GF(127), 3, [1,2,3,-1,2,5,2,3,1], sparse=True) |
| | 674 | sage: b = vector(GF(127),[1,2,3]) |
| | 675 | sage: x = A \ b; x |
| | 676 | (73, 76, 10) |
| | 677 | sage: A * x |
| | 678 | (1, 2, 3) |
| | 679 | |
| | 680 | """ |
| | 681 | cdef Matrix_modn_sparse A = self |
| | 682 | cdef Matrix_modn_sparse b |
| | 683 | cdef Matrix_modn_sparse X |
| | 684 | cdef c_vector_modint *x |
| | 685 | |
| | 686 | if algorithm == "generic" or not is_prime(self.p): |
| | 687 | return Matrix2.solve_right(self, B) |
| | 688 | |
| | 689 | if check_rank and self.rank() < self.nrows(): |
| | 690 | raise ValueError, "self must be of full rank." |
| | 691 | |
| | 692 | if not self.is_square(): |
| | 693 | raise NotImplementedError, "input matrix must be square" |
| | 694 | |
| | 695 | self._init_linbox() |
| | 696 | |
| | 697 | matrix = True |
| | 698 | if is_Vector(B): |
| | 699 | matrix = False |
| | 700 | b = <Matrix_modn_sparse>self.matrix_space(1, self.ncols(),sparse=True)(B.list()) |
| | 701 | if PY_TYPE_CHECK(B,Matrix_modn_sparse) and B.base_ring() == self.base_ring(): |
| | 702 | b = <Matrix_modn_sparse>B |
| | 703 | else: |
| | 704 | try: |
| | 705 | b = <Matrix_modn_sparse>self.matrix_space(1, self.ncols(),sparse=True)(B.list()) |
| | 706 | except (TypeError, AttributeError): |
| | 707 | raise TypeError, "parameter 'b' not understood." |
| | 708 | |
| | 709 | X = self.new_matrix(b.nrows(),A.ncols()) |
| | 710 | |
| | 711 | if b.nrows() > 1: # such that we can walk through it easily |
| | 712 | b = b.transpose() |
| | 713 | |
| | 714 | if algorithm is None: |
| | 715 | algorithm = 0 |
| | 716 | elif algorithm == "LinBox:BlasElimination": |
| | 717 | algorithm = 1 |
| | 718 | elif algorithm == "LinBox:Blackbox": |
| | 719 | algorithm = 2 |
| | 720 | elif algorithm == "LinBox:Wiedemann": |
| | 721 | algorithm = 3 |
| | 722 | else: |
| | 723 | raise TypeError, "parameter 'algorithm' not understood" |
| | 724 | |
| | 725 | for i in range(X.nrows()): |
| | 726 | _sig_on |
| | 727 | x = &X.rows[i] |
| | 728 | linbox.solve(&x, &b.rows[i], algorithm) |
| | 729 | _sig_off |
| | 730 | |
| | 731 | if not matrix: |
| | 732 | # Convert back to a vector |
| | 733 | return (X.base_ring() ** X.ncols())(X.list()) |
| | 734 | else: |
| | 735 | return X.transpose() |