Peter Bruin on Thu, 16 Jan 2014 14:25:11 +0100


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

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


Hello,

Bill Allombert <Bill.Allombert@math.u-bordeaux.fr> wrote:

>> The more I think about it, the more I actually prefer this approach to
>> the code duplication in my patch, so if you want to do it in this way,
>> I'll certainly be happy with that.
>
> Yes. Would you provide a patch for gen_matmul?

Here is a new patch using the bb_field interface.  In addition to the
previous patch, it implements FFM_FFC_mul, gen_matmul and gen_matcolmul;
I think we now have all matrix * matrix and matrix * column vector
functions over finite fields.

The matrix * matrix functions are covered by the current test suite, but
the matrix * column vector functions are not.

Best wishes,

Peter


PS: I just reported a bug (matrix multiplication 0x0 * 0xN -> 0x0
instead of 0xN); this patch is based on the one attached to that bug
report.


diff --git a/doc/develop.tex b/doc/develop.tex
index e5cfcae4..092c392 100644
--- a/doc/develop.tex
+++ b/doc/develop.tex
@@ -434,6 +434,10 @@ fields:
 
 \fun{GEN}{gen_matid}{long n, void *E, const struct bb_field *S}
 
+\fun{GEN}{gen_matcolmul}{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}
 
 \fun{const struct bb_field *}{get_Fp_field}{void **pt_E, GEN p}
diff --git a/doc/usersch5.tex b/doc/usersch5.tex
index 42680b3..06787cc 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,13 @@ 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_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}).
+
+\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 +9116,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..c5116b6 100644
--- a/src/basemath/FF.c
+++ b/src/basemath/FF.c
@@ -1738,3 +1738,39 @@ FFM_det(GEN M, GEN ff)
   }
   return gerepilecopy(av, mkFF_i(ff, d));
 }
+
+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_FFM(P, ff));
+}
+
+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 6ffa39a..efde7c2 100644
--- a/src/basemath/RgV.c
+++ b/src/basemath/RgV.c
@@ -408,14 +408,22 @@ RgM_RgC_mul_i(GEN x, GEN y, long lx, long l)
   for (i=1; i<l; i++) gel(z,i) = RgMrow_RgC_mul_i(x,y,i,lx);
   return z;
 }
+
 GEN
 RgM_RgC_mul(GEN x, GEN y)
 {
   long lx = lg(x);
+  GEN ffx = NULL, ffy = NULL;
   if (lx != lg(y)) pari_err_OP("operation 'RgM_RgC_mul'", x,y);
   if (lx == 1) return cgetg(1,t_COL);
+  if (RgM_is_FFM(x, &ffx) && RgC_is_FFC(y, &ffy)) {
+    if (!FF_samefield(ffx, ffy))
+      pari_err_OP("*", ffx, ffy);
+    return FFM_FFC_mul(x, y, ffx);
+  }
   return RgM_RgC_mul_i(x, y, lx, lgcols(x));
 }
+
 GEN
 RgV_RgM_mul(GEN x, GEN y)
 {
@@ -478,12 +486,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 zeromatcopy(0, ly-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..f2f9b95 100644
--- a/src/basemath/alglin1.c
+++ b/src/basemath/alglin1.c
@@ -360,6 +360,54 @@ gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff)
   return u;
 }
 
+/* compatible t_MAT * t_COL, lgA = lg(A) = lg(B) > 1, l = lgcols(A) */
+static GEN
+gen_matcolmul_i(GEN A, GEN B, ulong lgA, ulong l,
+		void *E, const struct bb_field *ff)
+{
+  GEN C = cgetg(l, t_COL);
+  ulong i;
+  for (i = 1; i < l; i++) {
+    pari_sp av = avma;
+    GEN e = ff->mul(E, gcoeff(A, i, 1), gel(B, 1));
+    long k;
+    for(k = 2; k < lgA; k++)
+      e = ff->add(E, e, ff->mul(E, gcoeff(A, i, k), gel(B, k)));
+    gel(C, i) = gerepileupto(av, ff->red(E, e));
+  }
+  return C;
+}
+
+GEN
+gen_matcolmul(GEN A, GEN B, void *E, const struct bb_field *ff)
+{
+  ulong lgA = lg(A);
+  if (lgA != lg(B))
+    pari_err_OP("operation 'gen_matcolmul'", A, B);
+  if (lgA == 1)
+    return cgetg(1, t_COL);
+  return gen_matcolmul_i(A, B, lgA, lgcols(A), E, ff);
+}
+
+GEN
+gen_matmul(GEN A, GEN B, void *E, const struct bb_field *ff)
+{
+  ulong j, l, lgA, lgB = lg(B);
+  GEN C;
+  if (lgB == 1)
+    return cgetg(1, t_MAT);
+  lgA = lg(A);
+  if (lgA != lgcols(B))
+    pari_err_OP("operation 'gen_matmul'", A, B);
+  if (lgA == 1)
+    return zeromatcopy(0, lgB - 1);
+  l = lgcols(A);
+  C = cgetg(lgB, t_MAT);
+  for(j = 1; j < lgB; j++)
+    gel(C, j) = gen_matcolmul_i(A, gel(B, j), lgA, l, E, ff);
+  return C;
+}
+
 static GEN
 image_from_pivot(GEN x, GEN d, long r)
 {
@@ -917,6 +965,21 @@ 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) {
+  void *E;
+  const struct bb_field *ff = get_Flxq_field(&E, T, p);
+  return gen_matcolmul(A, B, E, ff);
+}
+
+GEN
+FlxqM_mul(GEN A, GEN B, GEN T, unsigned long p) {
+  void *E;
+  const struct bb_field *ff = get_Flxq_field(&E, T, p);
+  return gen_matmul(A, B, E, ff);
+}
+
 GEN
 F2xqM_det(GEN a, GEN T)
 {
@@ -944,6 +1007,20 @@ F2xqM_inv(GEN a, GEN T)
   return gerepilecopy(av, u);
 }
 
+GEN
+F2xqM_F2xqC_mul(GEN A, GEN B, GEN T) {
+  void *E;
+  const struct bb_field *ff = get_F2xq_field(&E, T);
+  return gen_matcolmul(A, B, E, ff);
+}
+
+GEN
+F2xqM_mul(GEN A, GEN B, GEN T) {
+  void *E;
+  const struct bb_field *ff = get_F2xq_field(&E, T);
+  return gen_matmul(A, B, E, ff);
+}
+
 static GEN
 FqM_gauss_pivot_gen(GEN x, GEN T, GEN p, long *rr)
 {
@@ -992,6 +1069,20 @@ 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) {
+  void *E;
+  const struct bb_field *ff = get_Fq_field(&E, T, p);
+  return gen_matcolmul(A, B, E, ff);
+}
+
+GEN
+FqM_mul(GEN A, GEN B, GEN T, GEN p) {
+  void *E;
+  const struct bb_field *ff = get_Fq_field(&E, T, p);
+  return gen_matmul(A, B, E, ff);
+}
+
 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..ef9d85d 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);
@@ -1035,6 +1041,8 @@ 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_matcolmul(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);
 GEN     imagecompl(GEN x);
@@ -2190,10 +2198,12 @@ 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_mul(GEN M, GEN C, GEN ff);
 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);