Peter Bruin on Tue, 28 Apr 2015 00:42:59 +0200


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

Re: Strassen multiplication over the integers


Hello Bill,

> I have applied your patch with very minor modifications.

Merci !

> However there are things that need to be done.
>
> - ZM_sqr should be implemented as well.
>
> - gmul or RgM_mul should be changed to call ZM_mul when appropriate.

The above two points are addressed by the attached patch.  (Note that
the assumption that A == B in A*B doesn't really seem to simplify either
the classical algorithm or Strassen's algorithm.  Even the following
could be reasonable: "GEN ZM_sqr(GEN x) { return ZM_mul(x, x); }" ...)

> - the tuning should depend on the size of the coefficients, I think.

Certainly, for larger coefficients it is advantageous to use Strassen
multiplication already for smaller matrices.  I haven't yet done any
good experiments to see how the bound should depend on the maximum
coefficient size, though.

> - ideally the program src/test/tune.c should deal with the tuning.
> This program deal with dependencies between tuning parameters.

OK, I hope to have some time soon to try to write an addition for
src/test/tune.c for this.

> - Most of the code is fairly generic, so maybe there could be a
> gen_matmul_sw function.

Indeed, and I actually already have an implementation of exactly this
function, but it is an older version with awkward conventions for the
indices.  I will try to update this soon.  (Unfortunately it will be
hard to tune that one...)

Thanks,

Peter


diff --git a/src/basemath/RgV.c b/src/basemath/RgV.c
index 8bfaeea..98ef4c8 100644
--- a/src/basemath/RgV.c
+++ b/src/basemath/RgV.c
@@ -526,6 +526,8 @@ RgM_mul(GEN x, GEN y)
   lx = lg(x);
   if (lx != lgcols(y)) pari_err_OP("operation 'RgM_mul'", x,y);
   if (lx == 1) return zeromat(0,ly-1);
+  if (RgM_is_ZM(x) && RgM_is_ZM(y))
+    return ZM_mul(x, y);
   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))
@@ -628,6 +630,7 @@ RgM_sqr(GEN x)
   GEN z, ffx = NULL;
   if (lx == 1) return cgetg(1, t_MAT);
   if (lx != lgcols(x)) pari_err_OP("operation 'RgM_mul'", x,x);
+  if (RgM_is_ZM(x))         return ZM_sqr(x);
   if (is_modular_sqr(x,&z)) return gerepileupto(av, z);
   if (RgM_is_FFM(x, &ffx))  return FFM_mul(x, x, ffx);
   z = cgetg(lx, t_MAT);
diff --git a/src/basemath/ZV.c b/src/basemath/ZV.c
index 332b243..0b3cc3e 100644
--- a/src/basemath/ZV.c
+++ b/src/basemath/ZV.c
@@ -465,15 +465,22 @@ ZM_transmul(GEN x, GEN y)
   }
   return M;
 }
+
+static GEN
+ZM_sqr_i(GEN x, long l)
+{
+  if (l <= ZM_sw_bound)
+    return ZM_mul_classical(x, x, l, l, l);
+  else
+    return ZM_mul_sw(x, x, l - 1, l - 1, l - 1);
+}
+
 GEN
 ZM_sqr(GEN x)
 {
-  long j, l, lx=lg(x);
-  GEN z;
+  long lx=lg(x);
   if (lx==1) return cgetg(1,t_MAT);
-  l = lgcols(x); z = cgetg(lx,t_MAT);
-  for (j=1; j<lx; j++) gel(z,j) = ZM_ZC_mul_i(x, gel(x,j), lx, l);
-  return z;
+  return ZM_sqr_i(x, lx);
 }
 GEN
 ZM_ZC_mul(GEN x, GEN y)
@@ -564,7 +571,7 @@ _ZM_mul(void *data /*ignored*/, GEN x, GEN y)
 { (void)data; return ZM_mul(x,y); }
 static GEN
 _ZM_sqr(void *data /*ignored*/, GEN x)
-{ (void)data; return ZM_mul(x,x); }
+{ (void)data; return ZM_sqr(x); }
 GEN
 ZM_pow(GEN x, GEN n)
 {