Bill Allombert on Sat, 22 May 2010 19:56:56 +0200


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

Re: forqfvec (iterative qfminim)


Hello PARI-dev,

Ariel told me forqfvec did not work with non LLL reduced matrices,
so here a new patch that fix that, and a new example:

? my(z=vector(30));forqfvec(v,matid(8),30,z[v~*v]++);z
%1 = [8, 56, 224, 568, 1008, 1568, 2752, 4664, 6056, 7056, 10656,
15904, 17584, 19264, 28224, 37432, 39312, 42392, 54880, 71568, 77056,
74592, 97344, 130592, 126008, 123088, 163520, 195392, 195120, 197568]

Cheers,
Bill.
diff --git a/src/basemath/bibli1.c b/src/basemath/bibli1.c
index 69882e0..3b48975 100644
--- a/src/basemath/bibli1.c
+++ b/src/basemath/bibli1.c
@@ -1648,6 +1648,107 @@ addcolumntomatrix(GEN V, GEN invp, GEN L)
   return 1;
 }
 
+struct qfvec
+{
+  GEN a, r, u;
+};
+
+static void
+forqfvec_init(struct qfvec *qv, GEN a)
+{
+  if (typ(a) != t_MAT || !RgM_is_ZM(a)) pari_err(typeer, "forqfvec");
+  qv->u = lllgramint(a);
+  if (lg(qv->u) != lg(a)) pari_err(talker, "not a definite form in minim0");
+  qv->a = RgM_gtofp(qf_apply_ZM(a, qv->u), DEFAULTPREC);
+  qv->r = qfgaussred_positive(qv->a);
+  if (!qv->r) pari_err(precer, "minim0");
+}
+ 
+static void
+forqfvec(void *E, long (*fun)(void *, GEN, GEN, double), struct qfvec *qv, GEN BORNE)
+{
+  GEN x, a = qv->a, r = qv->r, u = qv->u;
+  long n = lg(a), i, j, k;
+  double p,BOUND,*v,*y,*z,**q;
+  const double eps = 0.0001;
+  if (!BORNE) BORNE = gen_0;
+  else
+  {
+    BORNE = gfloor(BORNE);
+    if (typ(BORNE) != t_INT) pari_err(typeer, "minim0");
+  }
+  minim_alloc(n, &q, &x, &y, &z, &v);
+  n--;
+  for (j=1; j<=n; j++)
+  {
+    v[j] = rtodbl(gcoeff(r,j,j));
+    for (i=1; i<j; i++) q[i][j] = rtodbl(gcoeff(r,i,j));
+  }
+
+  if (gequal0(BORNE))
+  {
+    double c;
+    p = rtodbl(gcoeff(a,1,1));
+    for (i=2; i<=n; i++) { c = rtodbl(gcoeff(a,i,i)); if (c < p) p = c; }
+    BORNE = roundr(dbltor(p));
+  }
+  else
+    p = gtodouble(BORNE);
+  BOUND = p * (1 + eps);
+  if (BOUND == p) pari_err(precer, "minim0");
+
+  k = n; y[n] = z[n] = 0;
+  x[n] = (long)sqrt(BOUND/v[n]);
+  for(;;x[1]--)
+  {
+    do
+    {
+      if (k>1)
+      {
+        long l = k-1;
+        z[l] = 0;
+        for (j=k; j<=n; j++) z[l] += q[l][j]*x[j];
+        p = (double)x[k] + z[k];
+        y[l] = y[k] + p*p*v[k];
+        x[l] = (long)floor(sqrt((BOUND-y[l])/v[l])-z[l]);
+        k = l;
+      }
+      for(;;)
+      {
+        p = (double)x[k] + z[k];
+        if (y[k] + p*p*v[k] <= BOUND) break;
+        k++; x[k]--;
+      }
+    } while (k > 1);
+    if (! x[1] && y[1]<=eps) break;
+
+    p = (double)x[1] + z[1]; p = y[1] + p*p*v[1]; /* norm(x) */
+    if (fun(E, u, x, p)) break;
+  }
+}
+
+static long
+_gp_forqf(void *E, GEN u, GEN x, double p)
+{
+  pari_sp av = avma;
+  set_lex(-1, ZM_zc_mul(u, x));
+  closure_evalvoid((GEN)E);
+  avma = av;
+  return loop_break();
+}
+
+void
+forqfvec0(GEN a, GEN BORNE, GEN code)
+{
+  pari_sp av = avma;
+  struct qfvec qv;
+  forqfvec_init(&qv, a);
+  push_lex(gen_0, code);
+  forqfvec((void*) code, &_gp_forqf, &qv, BORNE);
+  pop_lex(1);
+  avma = av;
+}
+
 /* Minimal vectors for the integral definite quadratic form: a.
  * Result u:
  *   u[1]= Number of vectors of square norm <= BORNE
diff --git a/src/functions/linear_algebra/forqfvec b/src/functions/linear_algebra/forqfvec
new file mode 100644
index 0000000..c3ee950
--- /dev/null
+++ b/src/functions/linear_algebra/forqfvec
@@ -0,0 +1,15 @@
+Function: forqfvec
+Section: linear_algebra
+C-Name: forqfvec0
+Prototype: vVGDGI
+Help:forqfvec(v,q,b,expr): q being a square and symmetric matrix
+ representing a positive definite quadratic form, evaluate expr for all
+ vector v such that q(v)<b.
+Doc: $q$ being a square and symmetric matrix representing a positive definite
+ quadratic form, evaluate \kbd{expr} for all vector $v$ such that $q(v)<b$.
+Variant: The following function is also available:
+ \fun{void}{forqfvec}{void *E, long (*fun)(void *, GEN, double), GEN q, GEN b}:
+ Evaluate \kbd{fun(E,v,m)} on all $v$ such that $q(v)<b$, where $v$ is a
+ \typ{VECSMALL} and $m=q(v)$ is a C double. The function \kbd{fun} must
+ return $0$, unless \kbd{forqfvec} should stop, in which case, it should
+ return $1$.
diff --git a/src/headers/paridecl.h b/src/headers/paridecl.h
index 2708168..9f83d4a 100644
--- a/src/headers/paridecl.h
+++ b/src/headers/paridecl.h
@@ -1084,6 +1084,7 @@ GEN     Q_from_QR(GEN x, long prec);
 GEN     R_from_QR(GEN x, long prec);
 GEN     algdep(GEN x, long n);
 GEN     algdep0(GEN x, long n, long bit);
+void    forqfvec0(GEN a, GEN BORNE, GEN code);
 GEN     gram_matrix(GEN M);
 GEN     lindep(GEN x);
 GEN     lindep0(GEN x, long flag);