Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Utility Functions for Matrices
The actual computation of homology groups ends up being linear algebra with the differentials thought of as matrices. This module contains some utility functions for this purpose. """
######################################################################## # Copyright (C) 2013 John H. Palmieri <palmieri@math.washington.edu> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ ########################################################################
# TODO: this module is a clear candidate for cythonizing. Need to # evaluate speed benefits.
""" Preprocess a matrix using the "Elimination algorithm" described by Dumas et al. [DHSW2003]_, and then call ``elementary_divisors`` on the resulting (smaller) matrix.
.. NOTE::
'snf' stands for 'Smith Normal Form'.
INPUT:
- ``mat`` -- an integer matrix, either sparse or dense.
(They use the transpose of the matrix considered here, so they use rows instead of columns.)
ALGORITHM:
Go through ``mat`` one column at a time. For each column, add multiples of previous columns to it until either
- it's zero, in which case it should be deleted. - its first nonzero entry is 1 or -1, in which case it should be kept. - its first nonzero entry is something else, in which case it is deferred until the second pass.
Then do a second pass on the deferred columns.
At this point, the columns with 1 or -1 in the first entry contribute to the rank of the matrix, and these can be counted and then deleted (after using the 1 or -1 entry to clear out its row). Suppose that there were `N` of these.
The resulting matrix should be much smaller; we then feed it to Sage's ``elementary_divisors`` function, and prepend `N` 1's to account for the rows deleted in the previous step.
EXAMPLES::
sage: from sage.homology.matrix_utils import dhsw_snf sage: mat = matrix(ZZ, 3, 4, range(12)) sage: dhsw_snf(mat) [1, 4, 0] sage: mat = random_matrix(ZZ, 20, 20, x=-1, y=2) sage: mat.elementary_divisors() == dhsw_snf(mat) True """ print("old matrix: %s by %s" % (rows, cols)) # leading_positions: dictionary of lists indexed by row: if first # nonzero entry in column c is in row r, then leading_positions[r] # should contain c # pass 1: print("starting pass 1") # new_col is a matrix with one column: sparse matrices seem to # be less buggy than sparse vectors (#5184, #5185), and # perhaps also faster. zero_cols += 1 else: # right now we don't check to see if entry divides # earlier, because we don't want to modify the # earlier columns of the matrix. Deal with this # in pass 2. else: else: # pass 2: # first eliminate the zero columns at the end print("starting pass 2") else: # at this point, jth should divide nth keep_columns.remove(n) zero_cols += 1 else: else: # pass 3: get rid of columns which start with 1 or -1 print("starting pass 3") else: # form the new matrix print("new matrix: %s by %s" % (new_mat.nrows(), new_mat.ncols())) else: ed = [1]*add_to_rank + new_mat.elementary_divisors() else: if verbose: print("new matrix: all pivots are 1 or -1") ed = [1]*add_to_rank
return ed + [0]*(rows - len(ed))
|