source: git/Singular/LIB/ncModslimgb.lib @ 167d4d

spielwiese
Last change on this file since 167d4d was 167d4d, checked in by Viktor Levandovskyy <levandov@…>, 4 years ago
updates in doc and some functions
  • Property mode set to 100644
File size: 16.9 KB
Line 
1//////////////////////////////////////////////////////////////////////////////
2version="version ncModslimgb.lib 4.1.2.0 Feb_2019 "; // $Id$
3category="Noncommutative";
4info="
5LIBRARY:  ncModslimgb.lib A library for computing Groebner bases over G-algebras
6                         defined over the rationals using modular techniques.
7
8AUTHORS: Wolfram Decker, Christian Eder, Viktor Levandovskyy, and
9Sharwan K. Tiwari shrawant@gmail.com
10
11REFERENCES:
12 Wolfram Decker, Christian Eder, Viktor Levandovskyy, and
13 Sharwan K. Tiwari, Modular Techniques For Noncommutative
14 Groebner Bases, https://link.springer.com/article/10.1007/s11786-019-00412-9
15 and https://arxiv.org/abs/1704.02852.
16
17 E. A. Arnold, Modular algorithms for computing Groebner bases.
18 Journal of Symbolic Computation 35, 403-419 (2003).
19
20 N. Idrees, G. Pfister, S. Steidel, Parallelization of Modular
21 Algorithms, Journal of Symbolic Computation 46, 672-684 (2011).
22
23PROCEDURES:
24 ncmodslimgb(ideal I, list #); Groebner basis of a given left ideal I
25 using modular methods (Chinese remainder theorem and Farey map).
26";
27
28LIB "parallel.lib";
29LIB "resources.lib";
30LIB "dmod.lib";
31
32static proc mod_init()
33{
34  newstruct("idealPrimeTestId", "ideal Ideal");
35}
36
37//==========================Main Procedure===================================
38proc ncmodslimgb(ideal I, list #)
39"USAGE:  ncmodslimgb(I[, exactness, ncores]); I ideal, optional integers exactness and n(umber of )cores
40RETURN:  ideal
41PURPOSE: compute a left Groebner basis of I by modular approach
42ASSUME: basering is a G-algebra; base field is prime field Q of rationals.
43NOTE:  - If the given algebra and ideal are graded (it is not checked by this command), then the computed Groebner
44basis will be exact. Otherwise, the result will be correct with a very high probability.
45- The optional parameter `exactness` justifies, whether the final (expensive)
46verification step will be performed or not (exactness=0, default value is 1).
47- The optional parameter `ncores` (default value is 1) provides an integer to use
48the number of cores (this must not exceed the number of available cores in the computing machine).
49EXAMPLE: example ncmodslimgb; shows an example
50"
51{
52  int ncores=1;      // default
53  int exactness = 1; // default
54  int sz=size(#);
55
56  if(sz>2)
57  {
58    ERROR("wrong optional parameters");
59  }
60
61  while(sz > 0)
62  {
63    if(typeof(#[sz]) == "int" && #[sz] == 0)
64    {
65      exactness = #[sz];
66    }
67    else
68    {
69      if(typeof(#[sz]) == "int" && #[sz] > 1)
70      {
71        ncores=setcores(#[sz]);
72      }
73    }
74    sz = sz-1;
75  }
76
77  def R0 = basering;
78  list rl = ringlist(R0);
79  if(rl[1][1] > 0)
80  {
81    ERROR("Characteristic of basering should be zero, basering should
82           have no parameters.");
83  }
84
85  //check the non-degenracy condition to ensure that the defined is
86  //a G-algbera
87  // V.L.: commented out, added ASSUME for basering to be a G-algebra
88  // ideal ndc = ndcond();
89  // if(ndc != 0)
90  // {
91    // ERROR("The given input is not a G-algebra");
92  // }
93
94  int index = 1;
95  int nextbp=1;
96  int i,k,c;
97  int j = 1;
98  int  pTest, sizeTest;
99  bigint N;
100
101  //Initialization of number of primes to be taken
102  int n2 = 20; //number of primes to be taken first time
103
104  if(ncores > 1)
105  {
106    int a = n2 % ncores;
107    if(a>0)
108    {
109      n2 = n2 - a + ncores;
110    }
111  }
112
113  //second round onwards, number of primes to be taken,
114  //one can decide;
115  int n3 = n2;     //default
116
117  intvec opt = option(get);
118  option(redSB);
119
120  //PrimeList procedure selects suitable primes such that
121  //these primes do not divide coefficients occuring
122  //in the generating polynomials of input ideal and
123  //in the defining relations of input algebra
124
125  intvec L = PrimeList(I, n2, ncores);
126
127  list P,T1,T2,LL;
128  int sizeT1;
129  int sizeT2;
130  ideal J,K,H;
131
132  // modular algorithm steps start here
133  list arguments_farey, results_farey, argumentpar;
134
135  while(1)
136  {
137    //sequential GB computation for the selected primes
138    if(ncores == 1)
139    {
140      while(nextbp <= size(L))
141      {
142        P = ModpSlim(I, L[nextbp]);
143        T1[index] = P[1];
144        T2[index] = bigint(P[2]);
145        index++;
146        nextbp++;
147      }
148    }
149    //GB computations in parallel for the  primes
150    else
151    {
152      argumentpar = list();
153      for(i = nextbp; i <= size(L); i++)
154      {
155        argumentpar[i-nextbp+1] = list(I,L[i]);
156      }
157      P = parallelWaitAll("ModpSlim",argumentpar, 0,ncores);
158
159      for(i = 1; i <= size(P); i++)
160      {
161        T1[i+sizeT1] = P[i][1];
162        T2[i+sizeT2] = bigint(P[i][2]);
163      }
164    }
165
166    LL = DeleteUnluckyPrimes(T1,T2);
167    T1 = LL[1];
168    T2 = LL[2];
169
170    //Lifting of results via CRT
171     N = T2[1];
172     for(i = 2; i <= size(T2); i++)
173     {
174       N = N*T2[i];
175     }
176     H = chinrem(T1,T2);
177
178    //Lifting of results to Rationals via Farey map
179    //sequential lifting
180     if(ncores == 1)
181     {
182       J = farey(H,N);
183     }
184    //parallel lifting
185    else
186    {
187      for(i = size(H); i > 0; i--)
188      {
189        arguments_farey[i] = list(ideal(H[i]), N);
190      }
191      results_farey = parallelWaitAll("farey", arguments_farey, 0, ncores);
192      for(i = size(H); i > 0; i--)
193      {
194        J[i] = results_farey[i][1];
195      }
196    }
197
198    //Verification steps
199    pTest = PTestGB(I,J,L,ncores);
200    if(pTest)
201    {
202      attrib(J,"isSB",1);
203      if(exactness == 0)
204      {
205        option(set, opt);
206        return(J);
207      }
208      if(exactness == 1)
209      {
210        //sizeTest = 1 - IsIncluded(I,J,ncores);
211        sizeTest = 1 - IsIncludedseq(I,J);
212        if(sizeTest == 0)
213        {
214          K = slimgb(J);
215          if(size(reduce(K,J)) == 0)
216          {
217            option(set, opt);
218            return(J);
219          }
220        }
221      }
222    }
223   // If, J is not Groebner basis of I
224   // compute for more number of primes
225    T1 = H;
226    sizeT1=size(T1);
227    T2 = N;
228    sizeT2=size(T2);
229    index = 2;
230    nextbp = size(L) + 1;
231    L = PrimeList(I,n3,L,ncores);
232  }
233}
234example
235{
236  "EXAMPLE:"; echo = 2;
237  ring r = 0,(x,y),dp;
238  poly P = y^4+x^3+x*y^3; // a (3,4)-Reiffen curve
239  def A = Sannfs(P); setring A; // computed D-module data from P
240  ideal bs = LD, imap(r,P); // preparing the computation of the Bernstein-Sato polynomial
241  ideal I1 = ncmodslimgb(bs,0,2); // no final verification, use 2 cores
242  I1[1]; // the Bernstein-Sato polynomial of P, univariate in s
243  ideal I2 = ncmodslimgb(bs); // do the final verification, use 1 core (default)
244  I2[1]; // the Bernstein-Sato polynomial of P, univariate in s
245}
246
247/*
248  ring r = 0,(x,y,z),Dp;
249  poly F = x^3+y^3+z^3;
250  def A  = Sannfs(F);
251  setring A;
252  ideal I=LD,imap(r,F) ;
253  ideal J=ncmodslimgb(I);
254*/
255
256static proc PrimeList(ideal I, int n, list #)
257"USAGE:  PrimeList(I,n[,ncores]); ( resp. PrimeList(I,n[,L,ncores]); ) I ideal,
258         n an integer
259RETURN:  n number of primes <= 2147483647 such that these primes do not divide
260         any coefficient of any generating polynomial of I.
261EXAMPLE: example PrimeList; shows an example
262{
263  intvec L;
264  int i,p;
265  int ncores = 1;
266
267 //Initialize optional parameter ncores
268  if(size(#) > 0)
269  {
270    if(size(#) == 1)
271    {
272      if(typeof(#[1]) == "int")
273      {
274        ncores = #[1];
275        # = list();
276      }
277    }
278    else
279    {
280      ncores = #[2];
281    }
282  }
283  if(size(#) == 0)
284  {
285    p = 2147483647;
286
287    //largest prime which can be represented as an @code{int} in Singular
288    while(!PrimeTestId(I,p) || !PrimeTestCommutatorRel(p))
289    {
290      p = prime(p-1);
291      if(p == 2)
292      {
293        ERROR("no more primes");
294      }
295    }
296    L[1] = p;
297  }
298  else
299  {
300    L = #[1];
301    p = prime(L[size(L)]-1);
302    while(!PrimeTestId(I,p) || !PrimeTestCommutatorRel(p))
303    {
304      p = prime(p-1);
305      if(p == 2)
306      {
307        ERROR("no more primes");
308      }
309    }
310    L[size(L)+1] = p;
311  }
312  if(p == 2)
313  {
314    ERROR("no more primes");
315  }
316
317 //sequential selection of remaining n-1  suitable primes
318  if(ncores == 1)
319  {
320    for(i = 2; i <= n; i++)
321    {
322      p = prime(p-1);
323      while(!PrimeTestId(I,p) || !PrimeTestCommutatorRel(p))
324      {
325        p = prime(p-1);
326        if(p == 2)
327        {
328          ERROR("no more primes");
329        }
330      }
331      L[size(L)+1] = p;
332    }
333  }
334 //parallel selection of remaining n-1 suitable primes
335  else
336  {
337    int neededSize = size(L)+n-1;;
338    list parallelResults;
339    list parallelResults2;
340    list arguments;
341    list arguments2;
342    int neededPrimes = neededSize-size(L);
343    idealPrimeTestId Id;
344    Id.Ideal = I;
345    export(Id);
346    while(neededPrimes > 0)
347    {
348      arguments = list();
349      for(i = ((neededPrimes div ncores)+1-(neededPrimes%ncores == 0)) *ncores;
350                                                                   i > 0; i--)
351      {
352        p = prime(p-1);
353        if(p == 2)
354        {
355          ERROR("no more primes");
356        }
357          arguments[i] = list("Id", p);
358          arguments2[i] = list(p);
359      }
360      parallelResults = parallelWaitAll("PrimeTestId", arguments, 0, ncores);
361
362      //check that primes are suitable for commutator relations
363      parallelResults2 = parallelWaitAll("PrimeTestCommutatorRel", arguments2,
364                                                                     0, ncores);
365
366      for(i = size(arguments); i > 0; i--)
367      {
368        if(parallelResults[i] && parallelResults2[i])
369        {
370          L[size(L)+1] = arguments[i][2];
371        }
372      }
373      neededPrimes = neededSize-size(L);
374    }
375    kill Id;
376    if(size(L) > neededSize)
377    {
378      L = L[1..neededSize];
379    }
380  }
381  return(L);
382}
383example
384{
385   "EXAMPLE:"; echo = 2;
386   ring r = 0,(x,y),dp;
387   def a = nc_algebra(2147483647, 1);
388   setring a;
389   ideal I = x+2147483629y, x3+y3;
390   intvec V = PrimeList(I,5);
391   V;
392   intvec W = PrimeList(I,5,2); // number of cores = 2
393   W;
394}
395
396static proc PrimeTestCommutatorRel(int p)
397"USAGE:  PrimeTestCommutatorRel(p); p a prime integer
398RETURN:  1 if p does not divide any coefficient of any defining relation of
399         G-algebra, 0 otherwise.
400EXAMPLE: example PrimeTestCommutatorRel; shows an example
401{
402  list rl = ringlist(basering);
403  matrix commrelmatC = rl[5];
404  matrix commrelmatD = rl[6];
405  int nvar=nvars(basering);
406  int i, j, k;
407  poly f; number cnt;
408
409
410  for(i = 1; i <= nvar; i++)
411  {
412    for(j = i+1; j <= nvar; j++)
413    {
414
415      cnt = leadcoef(commrelmatC[i,j]);
416
417      if(cnt == 0)
418      {
419        ERROR("wrong relations");
420      }
421      if((bigint(numerator(cnt)) mod p) == 0)
422      {
423        return(0);
424      }
425      if((bigint(denominator(cnt)) mod p) == 0)
426      {
427        return(0);
428      }
429    }
430  }
431  // checks for standard polynomials d_ij
432  for(i = 1; i <= nvar; i++)
433  {
434    for(j = i+1; j <= nvar; j++)
435    {
436      if(commrelmatD[i,j] != 0)
437      {
438        f = cleardenom(commrelmatD[i,j]);
439        cnt = leadcoef(commrelmatD[i,j])/leadcoef(f);
440        if((bigint(numerator(cnt)) mod p) == 0)
441        {
442          return(0);
443        }
444        if((bigint(denominator(cnt)) mod p) == 0)
445        {
446          return(0);
447        }
448        for(k = size(f); k > 0; k--)
449        {
450          if((bigint(leadcoef(f[k])) mod p) == 0)
451          {
452            return(0);
453          }
454        }
455      }
456    }
457  }
458  return(1);
459}
460example
461{
462 "EXAMPLE:"; echo = 2;
463 ring r = 0,(x,y),dp;
464 def a = nc_algebra(2147483647,1);
465 setring a;
466 ideal I = x+2147483629y;
467 int p1 = 2147483647;
468 int p2 = 2147483629;
469 int p3 = 2147483549;
470 PrimeTestCommutatorRel(p1);
471 PrimeTestCommutatorRel(p2);
472 PrimeTestCommutatorRel(p3);
473}
474
475static proc PrimeTestId(def II, bigint p)
476"USAGE:  PrimeTestId(I, p); I ideal, p a prime integer
477RETURN:  1 if p does not divide any numerator or denominator of any coefficient
478         in any polynomial of I, 0 otherwise.
479EXAMPLE: example PrimeTestId; shows an example
480{
481  if(typeof(II) == "string")
482  {
483    ideal I = `II`.Ideal;
484  }
485  else
486  {
487    ideal I = II;
488  }
489  I = simplify(I, 2);
490  int i,j;
491  poly f;
492  number cnt;
493
494  for(i = 1; i <= size(I); i++)
495  {
496    f = cleardenom(I[i]);
497    if(f == 0)
498    {
499      return(0);
500    }
501    cnt = leadcoef(I[i])/leadcoef(f);
502    if((bigint(numerator(cnt)) mod p) == 0)
503    {
504      return(0);
505    }
506    if((bigint(denominator(cnt)) mod p) == 0)
507    {
508      return(0);
509    }
510    for(j = size(f); j > 0; j--)
511    {
512      if((bigint(leadcoef(f[j])) mod p) == 0)
513      {
514        return(0);
515      }
516    }
517  }
518  return(1);
519}
520example
521{
522 "EXAMPLE:"; echo = 2;
523 ring r = 0,(x,y),dp;
524 def a = nc_algebra(2147483647,1);
525 setring a;
526 ideal I = x+2147483629y;
527 int p1 = 2147483647;
528 int p2 = 2147483629;
529 int p3 = 2147483549;
530 PrimeTestId(I,p1);
531 PrimeTestId(I,p2);
532 PrimeTestId(I,p3);
533}
534
535static proc ModpSlim(ideal I, int p)
536"USAGE:  ModpSlim(I, p); I ideal, p a prime
537RETURN:  The reduced Groebner basis of I mod p.
538ASSUME:  The base field is precisely Q.
539EXAMPLE: example ModpSlim; shows an example
540{
541  def R0 = basering;
542  list rl = ringlist(R0);
543
544  matrix commrelmatC = rl[5];
545  matrix commrelmatD = rl[6];
546  rl[1] = p;
547  def @rr = ring(rl);
548  setring @rr;
549  list rll = ringlist(@rr);
550
551  rll[5] = imap(R0,commrelmatC);
552  rll[6] = imap(R0,commrelmatD);
553  def @r = ring(rll);
554  setring @r;
555  kill @rr;
556  ideal ii = fetch(R0,I);
557  option(redSB);
558  ii = slimgb(ii);
559  setring R0;
560  return(list(fetch(@r,ii),p));
561}
562example
563{
564  "EXAMPLE:"; echo = 2;
565  def r = reiffen(4,5);
566  setring r;
567  def A = Sannfs(RC);
568  setring A;
569  ideal bs = LD, imap(r,RC);
570  int p = 2147483647;
571  list l = ModpSlim(bs, p);
572  l;
573}
574
575static proc DeleteUnluckyPrimes(list T, list L)
576{
577  int sizeModgbs = size(T);
578  list class;
579  int sizeClass;
580  ideal Lm;
581  int i;
582  int j;
583  for(i = 1; i <= sizeModgbs; i++)
584  {
585    Lm=lead(T[i]);
586    attrib(Lm, "isSB", 1);
587    for(j = 1; j <= sizeClass; j++)
588    {
589      if (size(Lm) == size(class[j][1])
590            && size(reduce(Lm, class[j][1])) == 0
591            && size(reduce(class[j][1], Lm)) == 0)
592      {
593        class[j][2] = class[j][2]+1;
594        class[j][3][class[j][2]] = i;
595        break;
596      }
597    }
598    if(j > sizeClass)
599    {
600      sizeClass++;
601      class[sizeClass]=list();
602      class[sizeClass][1]=Lm;
603      class[sizeClass][2]=1;
604      class[sizeClass][3]=list(i);
605    }
606  }
607  int classMax = 1;
608  int max = class[1][2];
609  for (i = 2; i <= sizeClass; i++)
610  {
611    if (class[i][2] > max)
612    {
613      ClassMax = i;
614      max = class[i][2];
615    }
616  }
617  list unluckyIndices;
618  for (i = 1; i <= sizeClass; i++)
619  {
620    if (i != classMax)
621    {
622      unluckyIndices = unluckyIndices + class[i][3];
623    }
624  }
625  for (i = size(unluckyIndices); i > 0; i--)
626  {
627    T = delete(T, unluckyIndices[i]);
628    L = delete(L, unluckyIndices[i]);
629  }
630  return(T,L);
631}
632
633static proc PTestGB(ideal I, ideal J, list L, int ncores)
634"USAGE:  PTestGB(I, J, L, ncores); I, J ideals, L intvec of primes
635RETURN:  1 (respectively 0) if for a randomly chosen prime p which is not in L
636         J mod p is (respectively is not) a Groebner basis of I mod p.
637"
638{
639  int i,k,p;
640  int ptest;
641  def R = basering;
642  list r = ringlist(R);
643  matrix commrelC = r[5];
644  matrix commrelD = r[6];
645  while(!ptest)
646  {
647    ptest = 1;
648    p = prime(random(1000000000,2134567879));
649    for(i = 1; i <= size(L); i++)
650    {
651      if(p == L[i])
652      {
653        ptest = 0;
654        break;
655      }
656    }
657    if(!PrimeTestCommutatorRel(p))
658    {
659      ptest = 0;
660    }
661    if(ptest)
662    {
663      for(i = 1; i <= ncols(J); i++)
664      {
665        for(k = 2; k <= size(J[i]); k++)
666        {
667          if((bigint(denominator(leadcoef(J[i][k]))) mod p) == 0)
668          {
669            ptest = 0;
670            break;
671          }
672        }
673        if(!ptest)
674        {
675          break;
676        }
677      }
678    }
679    if(ptest)
680    {
681      if(!PrimeTestId(I,p) )
682      {
683        ptest = 0;
684      }
685    }
686  }
687  r[1] = p;
688  def @RR = ring(r);
689  setring @RR;
690  list rr=ringlist(@RR);
691  rr[5]=imap(R,commrelC);
692  rr[6]=imap(R,commrelD);
693  def @R=ring(rr);
694  setring @R;
695  kill @RR;
696
697  ideal I = imap(R,I);
698  ideal J = imap(R, J);
699  attrib(J,"isSB",1);
700  ptest = 1;
701  //if(IsIncluded(I,J,ncores) == 0)
702  if(IsIncludedseq(I, J) == 0)
703  {
704    ptest = 0;
705  }
706
707  if(ptest)
708  {
709   ideal K = slimgb(I);
710    // if(IsIncludedseq(J, K,ncores) == 0)
711    if(IsIncludedseq(J, K) == 0)
712    {
713      ptest = 0;
714    }
715  }
716  setring R;
717  return(ptest);
718}
719
720proc IsIncludedseq(ideal I, ideal J, list #)
721"USAGE:  IsIncludedseq(I,J), where I, J are ideals
722RETURN:  1 if J includes I, 0  if there is a generating element f of I which
723         does not reduce to 0 with respect to J. The set of generators of J
724         should be a Groebner basis otherwise the result might not be correct.
725{
726  int i, k;
727  int ncores = 1;
728  //def R = basering;
729  //setring R;
730  attrib(J,"isSB",1);
731
732/*if( size(#) == 1)
733  {
734    if(typeof(#[1]) == "int")
735    {
736      ncores = #[1];
737    }
738  }*/
739  //sequential reduction
740  //if(ncores==1)
741  //{
742      for(k = 1; k <= ncols(I); k++)
743      {
744        if(reduce(I[k],J,1) != 0)
745        {
746          return(0);
747        }
748      }
749      return(1);
750 // }
751
752  //parallel reduction
753 /*
754  else
755  {
756    list args,results;
757    for(k = 1; k <= ncols(I); k++)
758    {
759      args[k] = list(ideal(I[k]),J,1);
760    }
761    option(notWarnSB);
762    results = parallelWaitAll("reduce",args, 0, ncores);
763    for(k=1; k <= size(results); k++)
764    {
765      if(results[k] != 0)
766      {
767        return(0);
768      }
769    }
770    return(1);
771  }*/
772}
773//===========================================================
Note: See TracBrowser for help on using the repository browser.