Peter Bruin on Mon, 13 Jan 2014 17:07:01 +0100


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

new FFM_mul (and FlxqM_mul, FqM_mul, ...)


Hello,

Here are a couple of functions for multiplying matrices over finite
fields.  I would be very happy if these functions (with any appropriate
improvements) could be included in the PARI library.

I implemented F2xqM_mul, FlxqM_mul, FqM_mul, the variants where the
right-hand side is a column vector (F2xqM_F2xqC_mul, etc.), and FFM_mul.
All of the functions are pretty straightforward.  I personally didn't
need FFM_FFC_mul or anything involving FFV, so I didn't implement those.
The patch also modifies RgM_mul to call FFM_mul when appropriate.  I ran
a small number of examples; the new functions seem to be up to 2.5 times
as fast as the existing code.

One thing I'm not sure about is how much consistency checking to do in
the lower-level functions (FlxqM_FlxqC_mul, etc.); currently they check
if the dimensions are compatible but not if the input types (t_MAT etc.)
are correct.

I also ran gcov and discovered that the new functions are covered by the
existing test suite, so I didn't add any new tests.

Thanks,

Peter


diff --git a/doc/usersch5.tex b/doc/usersch5.tex
index 42680b3..55159fc 100644
--- a/doc/usersch5.tex
+++ b/doc/usersch5.tex
@@ -3757,6 +3757,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_mul}{GEN a, GEN b, GEN T, GEN p}
+
 \fun{GEN}{FqM_ker}{GEN x, GEN T, GEN p} as \kbd{ker}
 
 \fun{GEN}{FqM_image}{GEN x, GEN T, GEN p} as \kbd{image}
@@ -3764,6 +3766,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_FqC_mul}{GEN a, GEN b, GEN T, GEN p}
+
 \fun{long}{FqM_rank}{GEN x, GEN T, GEN p} as \kbd{rank}
 
 \fun{GEN}{FqM_suppl}{GEN x, GEN T, GEN p} as \kbd{suppl}
@@ -4033,6 +4037,8 @@ and \kbd{y}
 
 \fun{GEN}{FlxqM_FlxqC_gauss}{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}
 
 \fun{GEN}{FlxqM_image}{GEN x, GEN T, ulong p}
@@ -4041,6 +4047,8 @@ and \kbd{y}
 
 \fun{GEN}{FlxqM_inv}{GEN x, 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}
 
 \fun{GEN}{matid_FlxqM}{long n, GEN T, ulong p}
@@ -5395,6 +5403,8 @@ $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_mul}{GEN a, GEN b, GEN T}
+
 \fun{GEN}{F2xqM_ker}{GEN x, GEN T}
 
 \fun{GEN}{F2xqM_det}{GEN a, GEN T}
@@ -5403,6 +5413,8 @@ $a=\sigma(X)$ where $\sigma$ is an automorphism of the algebra $\F_2[X]/T(X)$.
 
 \fun{GEN}{F2xqM_inv}{GEN a, GEN T}
 
+\fun{GEN}{F2xqM_mul}{GEN a, GEN b, GEN T}
+
 \fun{long}{F2xqM_rank}{GEN x, GEN T}
 
 \fun{GEN}{matid_F2xqM}{long n, GEN T}
@@ -9090,9 +9102,9 @@ 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_ker}{GEN M, GEN ff} return the kernel of the \typ{MAT} \kbd{M}
+\fun{GEN}{FFM_ker}{GEN M, GEN ff} returns the kernel of the \typ{MAT} \kbd{M}
 defined over the finite field given by the \typ{FFELT} \kbd{ff} (obtained
-by \tet{RgM_is_FFM(M,\&ff)}.
+by \tet{RgM_is_FFM(M,\&ff)}).
 
 \fun{GEN}{FFM_det}{GEN M, GEN ff}
 
@@ -9100,6 +9112,10 @@ by \tet{RgM_is_FFM(M,\&ff)}.
 
 \fun{GEN}{FFM_inv}{GEN M, GEN ff}
 
+\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}).
+
 \fun{long}{FFM_rank}{GEN M, GEN ff}
 
 \section{Transcendental functions}
diff --git a/src/basemath/FF.c b/src/basemath/FF.c
index 00aee57..2ec1395 100644
--- a/src/basemath/FF.c
+++ b/src/basemath/FF.c
@@ -1738,3 +1738,21 @@ FFM_det(GEN M, GEN ff)
   }
   return gerepilecopy(av, mkFF_i(ff, d));
 }
+
+GEN
+FFM_mul(GEN M, GEN N, GEN ff)
+{
+  pari_sp av = avma;
+  ulong pp;
+  GEN P, T, p;
+  _getFF(ff,&T,&p,&pp);
+  M = FFM_to_raw(M);
+  N = 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));
+}
diff --git a/src/basemath/RgV.c b/src/basemath/RgV.c
index c5dac90..4fab6d3 100644
--- a/src/basemath/RgV.c
+++ b/src/basemath/RgV.c
@@ -464,12 +464,17 @@ RgM_mul(GEN x, GEN y)
 {
   pari_sp av = avma;
   long j, l, lx, ly = lg(y);
-  GEN z;
+  GEN z, ffx = NULL, ffy = NULL;
   if (ly == 1) return cgetg(1,t_MAT);
   lx = lg(x);
   if (lx != lgcols(y)) pari_err_OP("operation 'RgM_mul'", x,y);
   if (lx == 1) return zeromat(0,lx-1);
   if (is_modular_mul(x,y,&z)) return gerepileupto(av, z);
+  if (RgM_is_FFM(x, &ffx) && RgM_is_FFM(y, &ffy)) {
+    if (!FF_samefield(ffx, ffy))
+      pari_err_OP("*", ffx, ffy);
+    return FFM_mul(x, y, ffx);
+  }
   z = cgetg(ly, t_MAT);
   l = lgcols(x);
   for (j=1; j<ly; j++) gel(z,j) = RgM_RgC_mul_i(x, gel(y,j), lx, l);
diff --git a/src/basemath/alglin1.c b/src/basemath/alglin1.c
index 43ccc91..ca4046f 100644
--- a/src/basemath/alglin1.c
+++ b/src/basemath/alglin1.c
@@ -917,6 +917,37 @@ FlxqM_det(GEN a, GEN T, ulong p)
   const struct bb_field *S = get_Flxq_field(&E, T, p);
   return gen_det(a, E, S);
 }
+
+GEN
+FlxqM_FlxqC_mul(GEN A, GEN B, GEN T, unsigned long p) {
+  long i, l, lgA = lg(A);
+  GEN C;
+  if(lgA != lg(B))
+    pari_err_OP("* [FlxqM_FlxqC]", A, B);
+  if(lgA == 1)
+    return cgetg(1, t_COL);
+  l = lgcols(A);
+  C = cgetg(l, t_COL);
+  for(i = 1; i < l; i++) {
+    pari_sp av = avma;
+    GEN e = Flx_mul(gcoeff(A, i, 1), gel(B, 1), p);
+    long k;
+    for(k = 2; k < lgA; k++)
+      e = Flx_add(e, Flx_mul(gcoeff(A, i, k), gel(B, k), p), p);
+    gel(C, i) = gerepileuptoleaf(av, Flx_rem(e, T, p));
+  }
+  return C;
+}
+
+GEN
+FlxqM_mul(GEN A, GEN B, GEN T, unsigned long p) {
+  long j, lgB = lg(B);
+  GEN C = cgetg(lgB, t_MAT);
+  for(j = 1; j < lgB; j++)
+    gel(C, j) = FlxqM_FlxqC_mul(A, gel(B, j), T, p);
+  return C;
+}
+
 GEN
 F2xqM_det(GEN a, GEN T)
 {
@@ -944,6 +975,36 @@ F2xqM_inv(GEN a, GEN T)
   return gerepilecopy(av, u);
 }
 
+GEN
+F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) {
+  long i, l, lgA = lg(A);
+  GEN C;
+  if(lgA != lg(B))
+    pari_err_OP("* [F2xqM_F2xqC]", A, B);
+  if(lgA == 1)
+    return cgetg(1, t_COL);
+  l = lgcols(A);
+  C = cgetg(l, t_COL);
+  for(i = 1; i < l; i++) {
+    pari_sp av = avma;
+    GEN e = F2x_mul(gcoeff(A, i, 1), gel(B, 1));
+    long k;
+    for(k = 2; k < lgA; k++)
+      e = F2x_add(e, F2x_mul(gcoeff(A, i, k), gel(B, k)));
+    gel(C, i) = gerepileuptoleaf(av, F2x_rem(e, T));
+  }
+  return C;
+}
+
+GEN
+F2xqM_mul(GEN A, GEN B, GEN T) {
+  long j, lgB = lg(B);
+  GEN C = cgetg(lgB, t_MAT);
+  for(j = 1; j < lgB; j++)
+    gel(C, j) = F2xqM_F2xqC_mul(A, gel(B, j), T);
+  return C;
+}
+
 static GEN
 FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr)
 {
@@ -992,6 +1053,36 @@ FqM_det(GEN x, GEN T, GEN p)
   return gen_det(x, E, S);
 }
 
+GEN
+FqM_FqC_mul(GEN A, GEN B, GEN T, GEN p) {
+  long i, l, lgA = lg(A);
+  GEN C;
+  if(lgA != lg(B))
+    pari_err_OP("* [FqM_FqC]", A, B);
+  if(lgA == 1)
+    return cgetg(1, t_COL);
+  l = lgcols(A);
+  C = cgetg(l, t_COL);
+  for(i = 1; i < l; i++) {
+    pari_sp av = avma;
+    GEN e = FpX_mul(gcoeff(A, i, 1), gel(B, 1), p);
+    long k;
+    for(k = 2; k < lgA; k++)
+      e = FpX_add(e, FpX_mul(gcoeff(A, i, k), gel(B, k), p), p);
+    gel(C, i) = gerepileupto(av, FpX_rem(e, T, p));
+  }
+  return C;
+}
+
+GEN
+FqM_mul(GEN A, GEN B, GEN T, GEN p) {
+  long j, lgB = lg(B);
+  GEN C = cgetg(lgB, t_MAT);
+  for(j = 1; j < lgB; j++)
+    gel(C, j) = FqM_FqC_mul(A, gel(B, j), T, p);
+  return C;
+}
+
 static GEN
 FpM_ker_gen(GEN x, GEN p, long deplin)
 {
diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h
index 5ffb570..43ce0c0 100644
--- a/src/headers/paridecl.h
+++ b/src/headers/paridecl.h
@@ -954,10 +954,12 @@ 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_mul(GEN a, GEN b, GEN T);
 GEN     F2xqM_det(GEN a, 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_mul(GEN a, GEN b, GEN T);
 long    F2xqM_rank(GEN x, GEN T);
 GEN     Flm_Flc_gauss(GEN a, GEN b, ulong p);
 GEN     Flm_Flc_invimage(GEN mat, GEN y, ulong p);
@@ -974,11 +976,13 @@ 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_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_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);
 GEN     FpM_FpC_invimage(GEN m, GEN v, GEN p);
@@ -994,12 +998,14 @@ 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_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);
 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_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);
 GEN     QM_inv(GEN M, GEN dM);
@@ -2194,6 +2200,7 @@ GEN     FFM_det(GEN M, GEN ff);
 GEN     FFM_image(GEN M, GEN ff);
 GEN     FFM_inv(GEN M, 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);
 GEN     FFX_factor(GEN f, GEN x);
 GEN     FFX_roots(GEN f, GEN x);