Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
Function: mathnf Section: linear_algebra C-Name: mathnf0 Prototype: GD0,L, Help: mathnf(M,{flag=0}): (upper triangular) Hermite normal form of M, basis for the lattice formed by the columns of M. flag is optional whose value range from 0 to 3 have a binary meaning. Bit 1: complete output, returns a 2-component vector [H,U] such that H is the HNF of M, and U is an invertible matrix such that MU=H. Bit 2: allow polynomial entries, otherwise assume that M is integral. These use a naive algorithm; larger values correspond to more involved algorithms and are restricted to integer matrices; flag = 4: returns [H,U] using LLL reduction along the way; flag = 5: return [H,U,P] where P is a permutation of row indices such that P applied to M U is H. Doc: let $R$ be a Euclidean ring, equal to $\Z$ or to $K[X]$ for some field $K$. If $M$ is a (not necessarily square) matrix with entries in $R$, this routine finds the \emph{upper triangular} \idx{Hermite normal form} of $M$. If the rank of $M$ is equal to its number of rows, this is a square matrix. In general, the columns of the result form a basis of the $R$-module spanned by the columns of $M$. The values of $\fl$ are: \item 0 (default): only return the Hermite normal form $H$ \item 1 (complete output): return $[H,U]$, where $H$ is the Hermite normal form of $M$, and $U$ is a transformation matrix such that $MU=[0|H]$. The matrix $U$ belongs to $\text{GL}(R)$. When $M$ has a large kernel, the entries of $U$ are in general huge. \noindent For these two values, we use a naive algorithm, which behaves well in small dimension only. Larger values correspond to different algorithms, are restricted to \emph{integer} matrices, and all output the unimodular matrix $U$. From now on all matrices have integral entries. \item $\fl=4$, returns $[H,U]$ as in ``complete output'' above, using a variant of \idx{LLL} reduction along the way. The matrix $U$ is provably small in the $L_2$ sense, and often close to optimal; but the reduction is in general slow, although provably polynomial-time. If $\fl=5$, uses Batut's algorithm and output $[H,U,P]$, such that $H$ and $U$ are as before and $P$ is a permutation of the rows such that $P$ applied to $MU$ gives $H$. This is in general faster than $\fl=4$ but the matrix $U$ is usually worse; it is heuristically smaller than with the default algorithm. When the matrix is dense and the dimension is large (bigger than 100, say), $\fl = 4$ will be fastest. When $M$ has maximal rank, then \bprog H = mathnfmod(M, matdetint(M)) @eprog\noindent will be even faster. You can then recover $U$ as $M^{-1}H$. \bprog ? M = matrix(3,4,i,j,random([-5,5])) %1 = [ 0 2 3 0] [-5 3 -5 -5] [ 4 3 -5 4] ? [H,U] = mathnf(M, 1); ? U %3 = [-1 0 -1 0] [ 0 5 3 2] [ 0 3 1 1] [ 1 0 0 0] ? H %5 = [19 9 7] [ 0 9 1] [ 0 0 1] ? M*U %6 = [0 19 9 7] [0 0 9 1] [0 0 0 1] @eprog For convenience, $M$ is allowed to be a \typ{VEC}, which is then automatically converted to a \typ{MAT}, as per the \tet{Mat} function. For instance to solve the generalized extended gcd problem, one may use \bprog ? v = [116085838, 181081878, 314252913,10346840]; ? [H,U] = mathnf(v, 1); ? U %2 = [ 103 -603 15 -88] [-146 13 -1208 352] [ 58 220 678 -167] [-362 -144 381 -101] ? v*U %3 = [0, 0, 0, 1] @eprog\noindent This also allows to input a matrix as a \typ{VEC} of \typ{COL}s of the same length (which \kbd{Mat} would concatenate to the \typ{MAT} having those columns): \bprog ? v = [[1,0,4]~, [3,3,4]~, [0,-4,-5]~]; mathnf(v) %1 = [47 32 12] [ 0 1 0] [ 0 0 1] @eprog Variant: Also available are \fun{GEN}{hnf}{GEN M} ($\fl=0$) and \fun{GEN}{hnfall}{GEN M} ($\fl=1$). To reduce \emph{huge} relation matrices (sparse with small entries, say dimension $400$ or more), you can use the pair \kbd{hnfspec} / \kbd{hnfadd}. Since this is quite technical and the calling interface may change, they are not documented yet. Look at the code in \kbd{basemath/hnf\_snf.c}.