Peter Bruin on Thu, 12 Jan 2017 16:56:04 +0100 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
FFM_gauss, FFM_invimage and analogous functions |
Bonjour, A long time ago I implemented *_invimage functions for finite fields using the bb_field framework, but so far these have not been included in the PARI library. During the Atelier PARI/GP I discovered that also the *_gauss functions for finite fields of characteristic 2 and the FFM_* variants were still missing. I made a patch containing implementations of the following tests: F2xqM_F2xqC_invimage F2xqM_F2xqC_gauss F2xqM_gauss F2xqM_invimage FlxqM_FlxqC_invimage FlxqM_invimage FqM_FqC_invimage FqM_invimage FFM_FFC_gauss FFM_FFC_invimage FFM_gauss FFM_invimage gen_matcolvinvimage gen_matinvimage There are some new tests that cover all the new code as far as I can see, and an entry in usersch5.tex for each function. Here is an example of the resulting speed improvement. The set-up is as follows: ? t = ffgen(2017^3); ? M = matrix(100, 100, i, j, random(t)); ? N = matrix(100, 100, i, j, random(t)); Before: ? matsolve(M, N); ? ## *** last result computed in 475 ms. ? matinverseimage(M, N); ? ## *** last result computed in 343 ms. After: ? matsolve(M, N); ? ## *** last result computed in 190 ms. ? matinverseimage(M, N); ? ## *** last result computed in 225 ms. These functions simply use classical algorithms. The next step will hopefully be to use LQUP factorisation for all standard linear algebra operations on matrices above a certain size. Thanks, Peter
>From c80c85859df6a86ef618384349af961d582a7120 Mon Sep 17 00:00:00 2001 From: Peter Bruin <P.J.Bruin@math.leidenuniv.nl> Date: Thu, 12 Jan 2017 16:10:46 +0100 Subject: [PATCH] add FFM_gauss, FFM_invimage, FFM_FFC_gauss, FFM_FFC_invimage and supporting functions --- doc/usersch5.tex | 40 +++++++++++ src/basemath/FF.c | 109 ++++++++++++++++++++++------- src/basemath/alglin1.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++- src/headers/paridecl.h | 14 ++++ src/test/32/ff | 23 +++++- src/test/in/ff | 8 +++ 6 files changed, 351 insertions(+), 29 deletions(-) diff --git a/doc/usersch5.tex b/doc/usersch5.tex index 5de91e2..b74cd7f 100644 --- a/doc/usersch5.tex +++ b/doc/usersch5.tex @@ -3902,6 +3902,8 @@ as \kbd{gauss}, where $b$ is a \kbd{FqM}. \fun{GEN}{FqM_FqC_gauss}{GEN a, GEN b, GEN T, GEN p} as \kbd{gauss}, where $b$ is a \kbd{FqC}. +\fun{GEN}{FqM_FqC_invimage}{GEN a, GEN b, GEN T, GEN p} + \fun{GEN}{FqM_FqC_mul}{GEN a, GEN b, GEN T, GEN p} \fun{GEN}{FqM_ker}{GEN x, GEN T, GEN p} as \kbd{ker} @@ -3911,6 +3913,8 @@ as \kbd{gauss}, where $b$ is a \kbd{FqC}. \fun{GEN}{FqM_inv}{GEN x, GEN T, GEN p} returns the inverse of \kbd{x}, or \kbd{NULL} if \kbd{x} is not invertible. +\fun{GEN}{FqM_invimage}{GEN a, GEN b, GEN T, GEN p} + \fun{GEN}{FqM_mul}{GEN a, GEN b, GEN T, GEN p} \fun{long}{FqM_rank}{GEN x, GEN T, GEN p} as \kbd{rank} @@ -4229,6 +4233,8 @@ and \kbd{y} \fun{GEN}{FlxqM_FlxqC_gauss}{GEN a, GEN b, GEN T, ulong p} +\fun{GEN}{FlxqM_FlxqC_invimage}{GEN a, GEN b, GEN T, ulong p} + \fun{GEN}{FlxqM_FlxqC_mul}{GEN a, GEN b, GEN T, ulong p} \fun{GEN}{FlxqM_ker}{GEN x, GEN T, ulong p} @@ -4239,6 +4245,8 @@ and \kbd{y} \fun{GEN}{FlxqM_inv}{GEN x, GEN T, ulong p} +\fun{GEN}{FlxqM_invimage}{GEN a, GEN b, GEN T, ulong p} + \fun{GEN}{FlxqM_mul}{GEN a, GEN b, GEN T, ulong p} \fun{long}{FlxqM_rank}{GEN x, GEN T, ulong p} @@ -5891,16 +5899,24 @@ $a=\sigma(X)$ where $\sigma$ is an automorphism of the algebra $\F_2[X]/T(X)$. \subsec{\kbd{F2xqV}, \kbd{F2xqM}}. See \kbd{FqV}, \kbd{FqM} operations. +\fun{GEN}{F2xqM_F2xqC_gauss}{GEN a, GEN b, GEN T} + +\fun{GEN}{F2xqM_F2xqC_invimage}{GEN a, GEN b, GEN T} + \fun{GEN}{F2xqM_F2xqC_mul}{GEN a, GEN b, GEN T} \fun{GEN}{F2xqM_ker}{GEN x, GEN T} \fun{GEN}{F2xqM_det}{GEN a, GEN T} +\fun{GEN}{F2xqM_gauss}{GEN a, GEN b, GEN T} + \fun{GEN}{F2xqM_image}{GEN x, GEN T} \fun{GEN}{F2xqM_inv}{GEN a, GEN T} +\fun{GEN}{F2xqM_invimage}{GEN a, GEN b, GEN T} + \fun{GEN}{F2xqM_mul}{GEN a, GEN b, GEN T} \fun{long}{F2xqM_rank}{GEN x, GEN T} @@ -9149,10 +9165,14 @@ operate on black box fields: \fun{GEN}{gen_ker}{GEN x, long deplin, void *E, const struct bb_field *ff} +\fun{GEN}{gen_matcolinvimage}{GEN a, GEN b, void *E, const struct bb_field *ff} + \fun{GEN}{gen_matcolmul}{GEN a, GEN b, void *E, const struct bb_field *ff} \fun{GEN}{gen_matid}{long n, void *E, const struct bb_field *ff} +\fun{GEN}{gen_matinvimage}{GEN a, GEN b, void *E, const struct bb_field *ff} + \fun{GEN}{gen_matmul}{GEN a, GEN b, void *E, const struct bb_field *ff} \subsec{Functions returning black box fields} @@ -11196,6 +11216,16 @@ of the univariate polynomial \kbd{f} over the definition field of the \typ{FFELT} \kbd{a}. The coefficients of \kbd{f} must be of type \typ{INT}, \typ{INTMOD} or \typ{FFELT} and compatible with \kbd{a}. +\fun{GEN}{FFM_FFC_gauss}{GEN M, GEN C, GEN ff} given a matrix \kbd{M} +(\typ{MAT}) and a column vector \kbd{C} (\typ{COL}) over the finite +field given by \kbd{ff} (\typ{FFELT}) such that $M$ is invertible, +return the unique column vector $X$ such that $MX=C$. + +\fun{GEN}{FFM_FFC_invimage}{GEN M, GEN C, GEN ff} given a matrix +\kbd{M} (\typ{MAT}) and a column vector \kbd{C} (\typ{COL}) over the +finite field given by \kbd{ff} (\typ{FFELT}), return a column vector +\kbd{X} such that $MX=C$, or \kbd{NULL} if no such vector exists. + \fun{GEN}{FFM_FFC_mul}{GEN M, GEN C, GEN ff} returns the product of the matrix~\kbd{M} (\typ{MAT}) and the column vector~\kbd{C} (\typ{COL}) over the finite field given by \kbd{ff} (\typ{FFELT}). @@ -11206,10 +11236,20 @@ by \tet{RgM_is_FFM(M,\&ff)}). \fun{GEN}{FFM_det}{GEN M, GEN ff} +\fun{GEN}{FFM_gauss}{GEN M, GEN N, GEN ff} given two matrices \kbd{M} +and~\kbd{N} (\typ{MAT}) over the finite field given by \kbd{ff} +(\typ{FFELT}) such that $M$ is invertible, return the unique matrix +$X$ such that $MX=N$. + \fun{GEN}{FFM_image}{GEN M, GEN ff} \fun{GEN}{FFM_inv}{GEN M, GEN ff} +\fun{GEN}{FFM_invimage}{GEN M, GEN N, GEN ff} given two matrices +\kbd{M} and~\kbd{N} (\typ{MAT}) over the finite field given by +\kbd{ff} (\typ{FFELT}), return a matrix \kbd{X} such that $MX=N$, or +\kbd{NULL} if no such matrix exists. + \fun{GEN}{FFM_mul}{GEN M, GEN N, GEN ff} returns the product of the matrices \kbd{M} and~\kbd{N} (\typ{MAT}) over the finite field given by \kbd{ff} (\typ{FFELT}). diff --git a/src/basemath/FF.c b/src/basemath/FF.c index 887bfe7..c0165ca 100644 --- a/src/basemath/FF.c +++ b/src/basemath/FF.c @@ -1817,6 +1817,7 @@ FqM_to_FpXQM(GEN x, GEN T, GEN p) return y; } +/* for functions t_MAT -> t_MAT */ static GEN FFM_wrap(GEN M, GEN ff, GEN (*Fq)(GEN,GEN,GEN), GEN (*Flxq)(GEN,GEN,ulong), @@ -1836,6 +1837,56 @@ FFM_wrap(GEN M, GEN ff, GEN (*Fq)(GEN,GEN,GEN), if (!M) { avma = av; return NULL; } return gerepilecopy(av, raw_to_FFM(M, ff)); } + +/* for functions (t_MAT, t_MAT) -> t_MAT */ +static GEN +FFM_FFM_wrap(GEN M, GEN N, GEN ff, + GEN (*Fq)(GEN, GEN, GEN, GEN), + GEN (*Flxq)(GEN, GEN, GEN, ulong), + GEN (*F2xq)(GEN, GEN, GEN)) +{ + pari_sp av = avma; + ulong pp; + GEN T, p; + int is_sqr = M==N; + _getFF(ff, &T, &p, &pp); + M = FFM_to_raw(M); + N = is_sqr? M: FFM_to_raw(N); + switch(ff[1]) + { + case t_FF_FpXQ: M = Fq(M, N, T, p); if (M) M = FqM_to_FpXQM(M, T, p); + break; + case t_FF_F2xq: M = F2xq(M, N, T); break; + default: M = Flxq(M, N, T, pp); break; + } + if (!M) { avma = av; return NULL; } + return gerepilecopy(av, raw_to_FFM(M, ff)); +} + +/* for functions (t_MAT, t_COL) -> t_COL */ +static GEN +FFM_FFC_wrap(GEN M, GEN C, GEN ff, + GEN (*Fq)(GEN, GEN, GEN, GEN), + GEN (*Flxq)(GEN, GEN, GEN, ulong), + GEN (*F2xq)(GEN, GEN, GEN)) +{ + pari_sp av = avma; + ulong pp; + GEN T, p; + _getFF(ff, &T, &p, &pp); + M = FFM_to_raw(M); + C = FFC_to_raw(C); + switch(ff[1]) + { + case t_FF_FpXQ: C = Fq(M, C, T, p); if (C) C = FqC_to_FpXQC(C, T, p); + break; + case t_FF_F2xq: C = F2xq(M, C, T); break; + default: C = Flxq(M, C, T, pp); break; + } + if (!C) { avma = av; return NULL; } + return gerepilecopy(av, raw_to_FFC(C, ff)); +} + GEN FFM_ker(GEN M, GEN ff) { return FFM_wrap(M,ff, &FqM_ker,&FlxqM_ker,&F2xqM_ker); } @@ -1878,38 +1929,42 @@ FFM_det(GEN M, GEN ff) } GEN +FFM_FFC_gauss(GEN M, GEN C, GEN ff) +{ + return FFM_FFC_wrap(M, C, ff, FqM_FqC_gauss, + FlxqM_FlxqC_gauss, F2xqM_F2xqC_gauss); +} + +GEN +FFM_gauss(GEN M, GEN N, GEN ff) +{ + return FFM_FFM_wrap(M, N, ff, FqM_gauss, + FlxqM_gauss, F2xqM_gauss); +} + +GEN +FFM_FFC_invimage(GEN M, GEN C, GEN ff) +{ + return FFM_FFC_wrap(M, C, ff, FqM_FqC_invimage, + FlxqM_FlxqC_invimage, F2xqM_F2xqC_invimage); +} + +GEN +FFM_invimage(GEN M, GEN N, GEN ff) +{ + return FFM_FFM_wrap(M, N, ff, FqM_invimage, + FlxqM_invimage, F2xqM_invimage); +} + +GEN FFM_FFC_mul(GEN M, GEN C, GEN ff) { - pari_sp av = avma; - ulong pp; - GEN P, T, p; - _getFF(ff, &T, &p, &pp); - M = FFM_to_raw(M); - C = FFC_to_raw(C); - switch (ff[1]) - { - case t_FF_FpXQ: P = FqM_FqC_mul(M, C, T, p); break; - case t_FF_F2xq: P = F2xqM_F2xqC_mul(M, C, T); break; - default: P = FlxqM_FlxqC_mul(M, C, T, pp); break; - } - return gerepilecopy(av, raw_to_FFC(P, ff)); + return FFM_FFC_wrap(M, C, ff, FqM_FqC_mul, + FlxqM_FlxqC_mul, F2xqM_F2xqC_mul); } GEN FFM_mul(GEN M, GEN N, GEN ff) { - pari_sp av = avma; - ulong pp; - GEN P, T, p; - int is_sqr = M==N; - _getFF(ff, &T, &p, &pp); - M = FFM_to_raw(M); - N = is_sqr? M: FFM_to_raw(N); - switch (ff[1]) - { - case t_FF_FpXQ: P = FqM_mul(M, N, T, p); break; - case t_FF_F2xq: P = F2xqM_mul(M, N, T); break; - default: P = FlxqM_mul(M, N, T, pp); break; - } - return gerepilecopy(av, raw_to_FFM(P, ff)); + return FFM_FFM_wrap(M, N, ff, FqM_mul, FlxqM_mul, F2xqM_mul); } diff --git a/src/basemath/alglin1.c b/src/basemath/alglin1.c index b31b2fe..4f451ec 100644 --- a/src/basemath/alglin1.c +++ b/src/basemath/alglin1.c @@ -410,6 +410,107 @@ gen_matmul(GEN A, GEN B, void *E, const struct bb_field *ff) } static GEN +gen_colneg(GEN A, void *E, const struct bb_field *ff) +{ + long i, l; + GEN B = cgetg_copy(A, &l); + for (i = 1; i < l; i++) + gel(B, i) = ff->neg(E, gel(A, i)); + return B; +} + +static GEN +gen_matneg(GEN A, void *E, const struct bb_field *ff) +{ + long i, l; + GEN B = cgetg_copy(A, &l); + for (i = 1; i < l; i++) + gel(B, i) = gen_colneg(gel(A, i), E, ff); + return B; +} + +/* assume dim A >= 1, A invertible + upper triangular */ +static GEN +gen_matinv_upper_ind(GEN A, long index, void *E, const struct bb_field *ff) +{ + long n = lg(A) - 1, i, j; + GEN u = cgetg(n + 1, t_COL); + for (i = n; i > index; i--) + gel(u, i) = ff->s(E, 0); + gel(u, i) = ff->inv(E, gcoeff(A, i, i)); + for (i--; i > 0; i--) { + pari_sp av = avma; + GEN m = ff->neg(E, ff->mul(E, gcoeff(A, i, i + 1), gel(u, i + 1))); + for (j = i + 2; j <= n; j++) + m = ff->add(E, m, ff->neg(E, ff->mul(E, gcoeff(A, i, j), gel(u, j)))); + gel(u, i) = gerepileupto(av, ff->red(E, ff->mul(E, m, ff->inv(E, gcoeff(A, i, i))))); + } + return u; +} + +static GEN +gen_matinv_upper(GEN A, void *E, const struct bb_field *ff) +{ + long i, l; + GEN B = cgetg_copy(A, &l); + for (i = 1; i < l; i++) + gel(B,i) = gen_matinv_upper_ind(A, i, E, ff); + return B; +} + +/* find z such that A z = y. Return NULL if no solution */ +GEN +gen_matcolinvimage(GEN A, GEN y, void *E, const struct bb_field *ff) +{ + pari_sp av = avma; + long i, l = lg(A); + GEN M, x, t; + + M = gen_ker(shallowconcat(A, y), 0, E, ff); + i = lg(M) - 1; + if (!i) { avma = av; return NULL; } + + x = gel(M, i); + t = gel(x, l); + if (ff->equal0(t)) { avma = av; return NULL; } + + t = ff->neg(E, ff->inv(E, t)); + setlg(x, l); + for (i = 1; i < l; i++) + gel(x, i) = ff->red(E, ff->mul(E, t, gel(x, i))); + return gerepilecopy(av, x); +} + +/* find Z such that A Z = B. Return NULL if no solution */ +GEN +gen_matinvimage(GEN A, GEN B, void *E, const struct bb_field *ff) +{ + pari_sp av = avma; + GEN d, x, X, Y; + long i, j, nY, nA, nB; + x = gen_ker(shallowconcat(gen_matneg(A, E, ff), B), 0, E, ff); + /* AX = BY, Y in strict upper echelon form with pivots = 1. + * We must find T such that Y T = Id_nB then X T = Z. This exists + * iff Y has at least nB columns and full rank. */ + nY = lg(x) - 1; + nB = lg(B) - 1; + if (nY < nB) { avma = av; return NULL; } + nA = lg(A) - 1; + Y = rowslice(x, nA + 1, nA + nB); /* nB rows */ + d = cgetg(nB + 1, t_VECSMALL); + for (i = nB, j = nY; i >= 1; i--, j--) { + for (; j >= 1; j--) + if (!ff->equal0(gcoeff(Y, i, j))) { d[i] = j; break; } + if (!j) { avma = av; return NULL; } + } + /* reduce to the case Y square, upper triangular with 1s on diagonal */ + Y = vecpermute(Y, d); + x = vecpermute(x, d); + X = rowslice(x, 1, nA); + return gerepileupto(av, gen_matmul(X, gen_matinv_upper(Y, E, ff), E, ff)); +} + +static GEN image_from_pivot(GEN x, GEN d, long r) { GEN y; @@ -1024,6 +1125,13 @@ FlxqM_det(GEN a, GEN T, ulong p) } GEN +FlxqM_FlxqC_invimage(GEN A, GEN B, GEN T, ulong p) { + void *E; + const struct bb_field *ff = get_Flxq_field(&E, T, p); + return gen_matcolinvimage(A, B, E, ff); +} + +GEN FlxqM_FlxqC_mul(GEN A, GEN B, GEN T, ulong p) { void *E; const struct bb_field *ff = get_Flxq_field(&E, T, p); @@ -1045,6 +1153,13 @@ FlxqM_mul(GEN A, GEN B, GEN T, ulong p) { } GEN +FlxqM_invimage(GEN A, GEN B, GEN T, ulong p) { + void *E; + const struct bb_field *ff = get_Flxq_field(&E, T, p); + return gen_matinvimage(A, B, E, ff); +} + +GEN F2xqM_det(GEN a, GEN T) { void *E; @@ -1059,6 +1174,19 @@ F2xqM_gauss_gen(GEN a, GEN b, GEN T) const struct bb_field *S = get_F2xq_field(&E, T); return gen_Gauss(a, b, E, S); } + +GEN +F2xqM_gauss(GEN a, GEN b, GEN T) +{ + pari_sp av = avma; + long n = lg(a)-1; + GEN u; + if (!n || lg(b)==1) { avma = av; return cgetg(1, t_MAT); } + u = F2xqM_gauss_gen(a, b, T); + if (!u) { avma = av; return NULL; } + return gerepilecopy(av, u); +} + GEN F2xqM_inv(GEN a, GEN T) { @@ -1071,6 +1199,24 @@ F2xqM_inv(GEN a, GEN T) } GEN +F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T) +{ + pari_sp av = avma; + GEN u; + if (lg(a) == 1) return cgetg(1, t_COL); + u = F2xqM_gauss_gen(a, mkmat(b), T); + if (!u) { avma = av; return NULL; } + return gerepilecopy(av, gel(u,1)); +} + +GEN +F2xqM_F2xqC_invimage(GEN A, GEN B, GEN T) { + void *E; + const struct bb_field *ff = get_F2xq_field(&E, T); + return gen_matcolinvimage(A, B, E, ff); +} + +GEN F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) { void *E; const struct bb_field *ff = get_F2xq_field(&E, T); @@ -1084,6 +1230,13 @@ F2xqM_mul(GEN A, GEN B, GEN T) { return gen_matmul(A, B, E, ff); } +GEN +F2xqM_invimage(GEN A, GEN B, GEN T) { + void *E; + const struct bb_field *ff = get_F2xq_field(&E, T); + return gen_matinvimage(A, B, E, ff); +} + static GEN FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr) { @@ -1133,6 +1286,13 @@ FqM_det(GEN x, GEN T, GEN p) } GEN +FqM_FqC_invimage(GEN A, GEN B, GEN T, GEN p) { + void *E; + const struct bb_field *ff = get_Fq_field(&E, T, p); + return gen_matcolinvimage(A, B, E, ff); +} + +GEN FqM_FqC_mul(GEN A, GEN B, GEN T, GEN p) { void *E; const struct bb_field *ff = get_Fq_field(&E, T, p); @@ -1146,6 +1306,13 @@ FqM_mul(GEN A, GEN B, GEN T, GEN p) { return gen_matmul(A, B, E, ff); } +GEN +FqM_invimage(GEN A, GEN B, GEN T, GEN p) { + void *E; + const struct bb_field *ff = get_Fq_field(&E, T, p); + return gen_matinvimage(A, B, E, ff); +} + static GEN FpM_ker_gen(GEN x, GEN p, long deplin) { @@ -1597,7 +1764,14 @@ RgM_solve(GEN a, GEN b) GEN p, u, data, ff = NULL; if (is_modular_solve(a,b,&u)) return gerepileupto(av, u); - if (!b && RgM_is_FFM(a, &ff)) return FFM_inv(a, ff); + if (RgM_is_FFM(a, &ff)) { + if (!b) + return FFM_inv(a, ff); + if (typ(b) == t_COL && RgC_is_FFC(b, &ff)) + return FFM_FFC_gauss(a, b, ff); + if (typ(b) == t_MAT && RgM_is_FFM(b, &ff)) + return FFM_gauss(a, b, ff); + } avma = av; if (lg(a)-1 == 2 && nbrows(a) == 2) { @@ -3048,6 +3222,11 @@ RgM_RgC_invimage(GEN A, GEN y) if (l==1) return NULL; if (lg(y) != lgcols(A)) pari_err_DIM("inverseimage"); + { + GEN ff = NULL; + if (RgM_is_FFM(A, &ff) && RgC_is_FFC(y, &ff)) + return FFM_FFC_invimage(A, y, ff); + } M = ker(shallowconcat(A, y)); i = lg(M)-1; if (!i) { avma = av; return NULL; } @@ -3291,6 +3470,11 @@ RgM_invimage(GEN A, GEN B) if (!x) { avma = av; return NULL; } return gerepileupto(av, x); } + { + GEN ff = NULL; + if (RgM_is_FFM(A, &ff) && RgM_is_FFM(B, &ff)) + return FFM_invimage(A, B, ff); + } x = ker(shallowconcat(RgM_neg(A), B)); /* AX = BY, Y in strict upper echelon form with pivots = 1. * We must find T such that Y T = Id_nB then X T = Z. This exists iff diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h index 9cd3290..ae978bc 100644 --- a/src/headers/paridecl.h +++ b/src/headers/paridecl.h @@ -1347,11 +1347,15 @@ GEN F2m_ker(GEN x); GEN F2m_ker_sp(GEN x, long deplin); long F2m_rank(GEN x); GEN F2m_suppl(GEN x); +GEN F2xqM_F2xqC_gauss(GEN a, GEN b, GEN T); +GEN F2xqM_F2xqC_invimage(GEN a, GEN b, GEN T); GEN F2xqM_F2xqC_mul(GEN a, GEN b, GEN T); GEN F2xqM_det(GEN a, GEN T); +GEN F2xqM_gauss(GEN a, GEN b, GEN T); GEN F2xqM_ker(GEN x, GEN T); GEN F2xqM_image(GEN x, GEN T); GEN F2xqM_inv(GEN a, GEN T); +GEN F2xqM_invimage(GEN a, GEN b, GEN T); GEN F2xqM_mul(GEN a, GEN b, GEN T); long F2xqM_rank(GEN x, GEN T); GEN Flm_Flc_gauss(GEN a, GEN b, ulong p); @@ -1370,12 +1374,14 @@ GEN Flm_ker_sp(GEN x, ulong p, long deplin); long Flm_rank(GEN x, ulong p); GEN Flm_suppl(GEN x, ulong p); GEN FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p); +GEN FlxqM_FlxqC_invimage(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_FlxqC_mul(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_det(GEN a, GEN T, ulong p); GEN FlxqM_gauss(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_ker(GEN x, GEN T, ulong p); GEN FlxqM_image(GEN x, GEN T, ulong p); GEN FlxqM_inv(GEN x, GEN T, ulong p); +GEN FlxqM_invimage(GEN a, GEN b, GEN T, ulong p); GEN FlxqM_mul(GEN a, GEN b, GEN T, ulong p); long FlxqM_rank(GEN x, GEN T, ulong p); GEN FpM_FpC_gauss(GEN a, GEN b, GEN p); @@ -1392,6 +1398,7 @@ GEN FpM_ker(GEN x, GEN p); long FpM_rank(GEN x, GEN p); GEN FpM_suppl(GEN x, GEN p); GEN FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p); +GEN FqM_FqC_invimage(GEN a, GEN b, GEN T, GEN p); GEN FqM_FqC_mul(GEN a, GEN b, GEN T, GEN p); GEN FqM_deplin(GEN x, GEN T, GEN p); GEN FqM_det(GEN x, GEN T, GEN p); @@ -1399,6 +1406,7 @@ GEN FqM_gauss(GEN a, GEN b, GEN T, GEN p); GEN FqM_ker(GEN x, GEN T, GEN p); GEN FqM_image(GEN x, GEN T, GEN p); GEN FqM_inv(GEN x, GEN T, GEN p); +GEN FqM_invimage(GEN a, GEN b, GEN T, GEN p); GEN FqM_mul(GEN a, GEN b, GEN T, GEN p); long FqM_rank(GEN a, GEN T, GEN p); GEN FqM_suppl(GEN x, GEN T, GEN p); @@ -1438,7 +1446,9 @@ GEN gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff); GEN gen_det(GEN a, void *E, const struct bb_field *ff); GEN gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff); +GEN gen_matcolinvimage(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_matcolmul(GEN a, GEN b, void *E, const struct bb_field *ff); +GEN gen_matinvimage(GEN a, GEN b, void *E, const struct bb_field *ff); GEN gen_matmul(GEN a, GEN b, void *E, const struct bb_field *ff); GEN image(GEN x); GEN image2(GEN x); @@ -2934,10 +2944,14 @@ GEN FF_to_FpXQ(GEN x); GEN FF_to_FpXQ_i(GEN x); GEN FF_trace(GEN x); GEN FF_zero(GEN a); +GEN FFM_FFC_invimage(GEN M, GEN C, GEN ff); +GEN FFM_FFC_gauss(GEN M, GEN C, GEN ff); GEN FFM_FFC_mul(GEN M, GEN C, GEN ff); GEN FFM_det(GEN M, GEN ff); +GEN FFM_gauss(GEN M, GEN N, GEN ff); GEN FFM_image(GEN M, GEN ff); GEN FFM_inv(GEN M, GEN ff); +GEN FFM_invimage(GEN M, GEN N, GEN ff); GEN FFM_ker(GEN M, GEN ff); GEN FFM_mul(GEN M, GEN N, GEN ff); long FFM_rank(GEN M, GEN ff); diff --git a/src/test/32/ff b/src/test/32/ff index 65c979c..cf08fa6 100644 --- a/src/test/32/ff +++ b/src/test/32/ff @@ -187,7 +187,7 @@ Mod(6687681666819568403, 18446744073944432641) ? conjvec(Mod(x,x^2+Mod(1,3))) [Mod(Mod(1, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3)), Mod(Mod(2, 3)*x, Mod(1, 3)*x^2 + Mod(1, 3))]~ -? test(q)=my(t=ffgen(q,'t),m=[t,t^2,1+t^3;1+t,1+t^2,1+t^3]);print(matker(m));print(matimage(m));print(matrank(m));my(M=[t,2*t^0,3*t^0;t,t^2,1+t^3;1+t,1+t^2,1+t^3]);print(matdet(M));print(M^(-1)*M);my(v=[t^0,t^1,t^2]~);print(M*v);my(N=t*[0,1;0,0]);iferr(N^-1,e,,errname(e)=="e_INV"); +? test(q)=my(t=ffgen(q,'t),m=[t,t^2,1+t^3;1+t,1+t^2,1+t^3]);print(matker(m));print(matimage(m));print(matrank(m));my(M=[t,2*t^0,3*t^0;t,t^2,1+t^3;1+t,1+t^2,1+t^3]);print(matdet(M));print(M^(-1)*M);my(v=[t^0,t^1,t^2]~);print(M*v);print(M*matsolve(M,v)==v);print(M*matinverseimage(M,v)==v);print(matsolve(M,matid(3)*t^0)==M^(-1));print(matinverseimage(M,matid(3)*t^0)==M^(-1));my(N=t*[0,1;0,0]);iferr(N^-1,e,,errname(e)=="e_INV");iferr(matsolve(N,t*[0,1]~),e,,errname(e)=="e_INV");print(matinverseimage(N,t*[1,0]~));print(matinverseimage(N,t*[0,1]~));print(matinverseimage(N,N^0)); ? test(2^5) [t^4 + t^3; t^4 + t^3; 1] [t, t^2; t + 1, t^2 + 1] @@ -195,6 +195,13 @@ Mod(6687681666819568403, 18446744073944432641) t^4 + t^2 [1, 0, 0; 0, 1, 0; 0, 0, 1] [t^2 + t, t^4 + t^3 + 1, t^4 + t^3 + t]~ +1 +1 +1 +1 +[0, 1]~ +[]~ +[;] ? test(7^5) [3*t^4 + 5*t^3 + 6*t^2 + 2*t; 4*t^4 + 2*t^3 + t^2 + 5*t; 1] [t, t^2; t + 1, t^2 + 1] @@ -202,6 +209,13 @@ t^4 + t^2 6*t^4 + 2*t^3 + 4*t^2 + 2*t + 2 [1, 0, 0; 0, 1, 0; 0, 0, 1] [3*t^2 + 3*t, 6*t^4 + 5*t^3 + 4*t^2 + 5*t + 6, 6*t^4 + 5*t^3 + 4*t^2 + 6*t]~ +1 +1 +1 +1 +[0, 1]~ +[]~ +[;] ? test((2^64+13)^5) [3*t^4 + 5*t^3 + 18446744073709551621*t^2 + 18446744073709551617*t; 18446744 073709551626*t^4 + 18446744073709551624*t^3 + 8*t^2 + 12*t; 1] @@ -212,6 +226,13 @@ t^4 + t^2 [3*t^2 + 3*t, 18446744073709551628*t^4 + 5*t^3 + 4*t^2 + 1844674407370955162 7*t + 18446744073709551628, 18446744073709551628*t^4 + 5*t^3 + 4*t^2 + 18446 744073709551628*t]~ +1 +1 +1 +1 +[0, 1]~ +[]~ +[;] ? test(q)=my(t=ffgen(q,'t),M=matrix(10,10,i,j,random(t)));subst(charpoly(M),'x,M)==0; ? test(nextprime(2^7)^5) 1 diff --git a/src/test/in/ff b/src/test/in/ff index 7e18974..94bd6ab 100644 --- a/src/test/in/ff +++ b/src/test/in/ff @@ -72,8 +72,16 @@ test(q)= print(M^(-1)*M); my(v = [t^0, t^1, t^2]~); print(M*v); + print(M*matsolve(M, v) == v); + print(M*matinverseimage(M, v) == v); + print(matsolve(M, matid(3)*t^0) == M^(-1)); + print(matinverseimage(M, matid(3)*t^0) == M^(-1)); my(N = t*[0, 1; 0, 0]); iferr(N^-1, e,, errname(e) == "e_INV"); + iferr(matsolve(N, t*[0, 1]~), e,, errname(e) == "e_INV"); + print(matinverseimage(N, t*[1, 0]~)); + print(matinverseimage(N, t*[0, 1]~)); + print(matinverseimage(N, N^0)); } test(2^5) test(7^5) -- 2.7.3