Function: matsnf
Section: linear_algebra
C-Name: matsnf0
Prototype: GD0,L,
Help: matsnf(X,{flag=0}): Smith normal form (i.e. elementary divisors) of
 the matrix X, expressed as a vector d; X must have integer or polynomial
 entries. Binary digits of flag mean 1: returns
 [u,v,d] where d=u*X*v, otherwise only the diagonal d is returned,
 4: removes all information corresponding to entries equal to 1 in d.
Doc: if $X$ is a (singular or nonsingular) matrix outputs the vector of
 \idx{elementary divisors} of $X$, i.e.~the diagonal of the
 \idx{Smith normal form} of $X$, normalized so that $d_{n} \mid d_{n-1} \mid
 \ldots \mid d_{1}$. $X$ must have integer or polynomial entries; in the latter
 case, $X$ must be a square matrix.

 The binary digits of \fl\ mean:

 1 (complete output): if set, outputs $[U,V,D]$, where $U$ and $V$ are two
 unimodular matrices such that $UXV$ is the diagonal matrix $D$. Otherwise
 output only the diagonal of $D$. If $X$ is not a square matrix, then $D$
 will be a square diagonal matrix padded with zeros on the left or the top.

 4 (cleanup): if set, cleans up the output. This means that elementary
 divisors equal to $1$ will be deleted, i.e.~outputs a shortened vector $D'$
 instead of $D$. If complete output was required, returns $[U',V',D']$ so
 that $U'XV' = D'$ holds. If this flag is set, $X$ is allowed to be of the
 form `vector of elementary divisors' or $[U,V,D]$ as would normally be
 output with the cleanup flag unset.

 If $v$ is an output from \kbd{matsnf} and $p$ is a power of an irreducible
 element, then \kbd{snfrank(v, p)} returns the $p$-rank of the attached
 module.

 \bprog
 ? X = [27,0; 0,3; 1,1; 0,0]; matsnf(X)
 %1 = [0, 0, 3, 1]
 ? [U,V,D] = v = matsnf(X, 1); U*X*V == D
 %2
 ? U
 %3 =
 [0 0   0 1]

 [1 9 -27 0]

 [0 1   0 0]

 [0 0   1 0]

 ? V
 %4 =
 [-1 1]

 [ 1 0]

 ? snfrank(v, 3)
 %5 = 3
 @eprog\noindent Continuing the same example after cleanup:
 \bprog
 ? [U,V,D] = v = matsnf(X, 1+4); U*X*V == D
 %6 = 1

 ? D
 %7 =
 [0]

 [0]

 [3]

 ? snfrank(v, 3)
 %8 = 3

 ? snfrank(v, 2)
 %9 = 2
 @eprog
