Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - perm.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.14.0 lcov report (development 27775-aca467eab2) Lines: 952 1038 91.7 %
Date: 2022-07-03 07:33:15 Functions: 104 111 93.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2000-2003  The PARI group.
       2             : 
       3             : This file is part of the PARI/GP package.
       4             : 
       5             : PARI/GP is free software; you can redistribute it and/or modify it under the
       6             : terms of the GNU General Public License as published by the Free Software
       7             : Foundation; either version 2 of the License, or (at your option) any later
       8             : version. It is distributed in the hope that it will be useful, but WITHOUT
       9             : ANY WARRANTY WHATSOEVER.
      10             : 
      11             : Check the License for details. You should have received a copy of it, along
      12             : with the package; see the file 'COPYING'. If not, write to the Free Software
      13             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14             : 
      15             : #include "pari.h"
      16             : #include "paripriv.h"
      17             : 
      18             : /*************************************************************************/
      19             : /**                                                                     **/
      20             : /**                   Routines for handling VEC/COL                     **/
      21             : /**                                                                     **/
      22             : /*************************************************************************/
      23             : int
      24        1841 : vec_isconst(GEN v)
      25             : {
      26        1841 :   long i, l = lg(v);
      27             :   GEN w;
      28        1841 :   if (l==1) return 1;
      29        1841 :   w = gel(v,1);
      30        6342 :   for(i=2; i<l; i++)
      31        5768 :     if (!gequal(gel(v,i), w)) return 0;
      32         574 :   return 1;
      33             : }
      34             : 
      35             : int
      36       17634 : vecsmall_isconst(GEN v)
      37             : {
      38       17634 :   long i, l = lg(v);
      39             :   ulong w;
      40       17634 :   if (l==1) return 1;
      41       17634 :   w = uel(v,1);
      42       30582 :   for(i=2; i<l; i++)
      43       24564 :     if (uel(v,i) != w) return 0;
      44        6018 :   return 1;
      45             : }
      46             : 
      47             : /* Check if all the elements of v are different.
      48             :  * Use a quadratic algorithm. Could be done in n*log(n) by sorting. */
      49             : int
      50           0 : vec_is1to1(GEN v)
      51             : {
      52           0 :   long i, j, l = lg(v);
      53           0 :   for (i=1; i<l; i++)
      54             :   {
      55           0 :     GEN w = gel(v,i);
      56           0 :     for(j=i+1; j<l; j++)
      57           0 :       if (gequal(gel(v,j), w)) return 0;
      58             :   }
      59           0 :   return 1;
      60             : }
      61             : 
      62             : GEN
      63       98084 : vec_insert(GEN v, long n, GEN x)
      64             : {
      65       98084 :   long i, l=lg(v);
      66       98084 :   GEN V = cgetg(l+1,t_VEC);
      67      711340 :   for(i=1; i<n; i++) gel(V,i) = gel(v,i);
      68       98084 :   gel(V,n) = x;
      69      471646 :   for(i=n+1; i<=l; i++) gel(V,i) = gel(v,i-1);
      70       98084 :   return V;
      71             : }
      72             : /*************************************************************************/
      73             : /**                                                                     **/
      74             : /**                   Routines for handling VECSMALL                    **/
      75             : /**                                                                     **/
      76             : /*************************************************************************/
      77             : /* Sort v[0]...v[n-1] and put result in w[0]...w[n-1].
      78             :  * We accept v==w. w must be allocated. */
      79             : static void
      80   176195912 : vecsmall_sortspec(GEN v, long n, GEN w)
      81             : {
      82   176195912 :   pari_sp ltop=avma;
      83   176195912 :   long nx=n>>1, ny=n-nx;
      84             :   long m, ix, iy;
      85             :   GEN x, y;
      86   176195912 :   if (n<=2)
      87             :   {
      88   103944324 :     if (n==1)
      89    22601347 :       w[0]=v[0];
      90    81342977 :     else if (n==2)
      91             :     {
      92    85230448 :       long v0=v[0], v1=v[1];
      93    85230448 :       if (v0<=v1) { w[0]=v0; w[1]=v1; }
      94     3590522 :       else        { w[0]=v1; w[1]=v0; }
      95             :     }
      96   103944324 :     return;
      97             :   }
      98    72251588 :   x=new_chunk(nx); y=new_chunk(ny);
      99    79954561 :   vecsmall_sortspec(v,nx,x);
     100    80998437 :   vecsmall_sortspec(v+nx,ny,y);
     101   369852067 :   for (m=0, ix=0, iy=0; ix<nx && iy<ny; )
     102   283703221 :     if (x[ix]<=y[iy])
     103   235765707 :       w[m++]=x[ix++];
     104             :     else
     105    47937514 :       w[m++]=y[iy++];
     106    90203043 :   for(;ix<nx;) w[m++]=x[ix++];
     107   315268114 :   for(;iy<ny;) w[m++]=y[iy++];
     108    86148846 :   set_avma(ltop);
     109             : }
     110             : 
     111             : /*in place sort.*/
     112             : void
     113    36012473 : vecsmall_sort(GEN V)
     114             : {
     115    36012473 :   long l = lg(V)-1;
     116    36012473 :   if (l<=1) return;
     117    29937957 :   vecsmall_sortspec(V+1,l,V+1);
     118             : }
     119             : 
     120             : /* cf gen_sortspec */
     121             : static GEN
     122    18590951 : vecsmall_indexsortspec(GEN v, long n)
     123             : {
     124             :   long nx, ny, m, ix, iy;
     125             :   GEN x, y, w;
     126    18590951 :   switch(n)
     127             :   {
     128       19051 :     case 1: return mkvecsmall(1);
     129     5043469 :     case 2: return (v[1] <= v[2])? mkvecsmall2(1,2): mkvecsmall2(2,1);
     130     5189473 :     case 3:
     131     5189473 :       if (v[1] <= v[2]) {
     132     4451573 :         if (v[2] <= v[3]) return mkvecsmall3(1,2,3);
     133      228689 :         return (v[1] <= v[3])? mkvecsmall3(1,3,2)
     134      673685 :                              : mkvecsmall3(3,1,2);
     135             :       } else {
     136      737900 :         if (v[1] <= v[3]) return mkvecsmall3(2,1,3);
     137      318420 :         return (v[2] <= v[3])? mkvecsmall3(2,3,1)
     138      883492 :                              : mkvecsmall3(3,2,1);
     139             :       }
     140             :   }
     141     8338958 :   nx = n>>1; ny = n-nx;
     142     8338958 :   w = cgetg(n+1,t_VECSMALL);
     143     8338965 :   x = vecsmall_indexsortspec(v,nx);
     144     8338965 :   y = vecsmall_indexsortspec(v+nx,ny);
     145   150555452 :   for (m=1, ix=1, iy=1; ix<=nx && iy<=ny; )
     146   142216484 :     if (v[x[ix]] <= v[y[iy]+nx])
     147    91919391 :       w[m++] = x[ix++];
     148             :     else
     149    50297093 :       w[m++] = y[iy++]+nx;
     150    11292137 :   for(;ix<=nx;) w[m++] = x[ix++];
     151    56461889 :   for(;iy<=ny;) w[m++] = y[iy++]+nx;
     152     8338968 :   set_avma((pari_sp)w); return w;
     153             : }
     154             : 
     155             : /*indirect sort.*/
     156             : GEN
     157     1913091 : vecsmall_indexsort(GEN V)
     158             : {
     159     1913091 :   long l=lg(V)-1;
     160     1913091 :   if (l==0) return cgetg(1, t_VECSMALL);
     161     1913028 :   return vecsmall_indexsortspec(V,l);
     162             : }
     163             : 
     164             : /* assume V sorted */
     165             : GEN
     166       31449 : vecsmall_uniq_sorted(GEN V)
     167             : {
     168             :   GEN W;
     169       31449 :   long i,j, l = lg(V);
     170       31449 :   if (l == 1) return vecsmall_copy(V);
     171       31395 :   W = cgetg(l,t_VECSMALL);
     172       31395 :   W[1] = V[1];
     173       34342 :   for(i=j=2; i<l; i++)
     174        2947 :     if (V[i] != W[j-1]) W[j++] = V[i];
     175       31395 :   stackdummy((pari_sp)(W + l), (pari_sp)(W + j));
     176       31395 :   setlg(W, j); return W;
     177             : }
     178             : 
     179             : GEN
     180         439 : vecsmall_uniq(GEN V)
     181             : {
     182         439 :   pari_sp av = avma;
     183         439 :   V = zv_copy(V); vecsmall_sort(V);
     184         439 :   return gerepileuptoleaf(av, vecsmall_uniq_sorted(V));
     185             : }
     186             : 
     187             : /* assume x sorted */
     188             : long
     189           0 : vecsmall_duplicate_sorted(GEN x)
     190             : {
     191           0 :   long i,k,l=lg(x);
     192           0 :   if (l==1) return 0;
     193           0 :   for (k=x[1],i=2; i<l; k=x[i++])
     194           0 :     if (x[i] == k) return i;
     195           0 :   return 0;
     196             : }
     197             : 
     198             : long
     199       18315 : vecsmall_duplicate(GEN x)
     200             : {
     201       18315 :   pari_sp av=avma;
     202       18315 :   GEN p=vecsmall_indexsort(x);
     203       18315 :   long k,i,r=0,l=lg(x);
     204       18315 :   if (l==1) return 0;
     205       24964 :   for (k=x[p[1]],i=2; i<l; k=x[p[i++]])
     206        6649 :     if (x[p[i]] == k) { r=p[i]; break; }
     207       18315 :   set_avma(av);
     208       18315 :   return r;
     209             : }
     210             : 
     211             : static int
     212       54110 : vecsmall_is1to1spec(GEN v, long n, GEN w)
     213             : {
     214       54110 :   pari_sp ltop=avma;
     215       54110 :   long nx=n>>1, ny=n-nx;
     216             :   long m, ix, iy;
     217             :   GEN x, y;
     218       54110 :   if (n<=2)
     219             :   {
     220       32564 :     if (n==1)
     221       11151 :       w[0]=v[0];
     222       21413 :     else if (n==2)
     223             :     {
     224       21413 :       long v0=v[0], v1=v[1];
     225       21413 :       if (v0==v1) return 0;
     226       21399 :       else if (v0<v1) { w[0]=v0; w[1]=v1; }
     227        4688 :       else            { w[0]=v1; w[1]=v0; }
     228             :     }
     229       32550 :     return 1;
     230             :   }
     231       21546 :   x = new_chunk(nx);
     232       21546 :   if (!vecsmall_is1to1spec(v,nx,x))    return 0;
     233       21462 :   y = new_chunk(ny);
     234       21462 :   if (!vecsmall_is1to1spec(v+nx,ny,y)) return 0;
     235       84096 :   for (m=0, ix=0, iy=0; ix<nx && iy<ny; )
     236       62718 :     if (x[ix]==y[iy]) return 0;
     237       62669 :     else if (x[ix]<y[iy])
     238       37979 :       w[m++]=x[ix++];
     239             :     else
     240       24690 :       w[m++]=y[iy++];
     241       23495 :   for(;ix<nx;) w[m++]=x[ix++];
     242       52870 :   for(;iy<ny;) w[m++]=y[iy++];
     243       21378 :   set_avma(ltop);
     244       21378 :   return 1;
     245             : }
     246             : 
     247             : int
     248       11200 : vecsmall_is1to1(GEN V)
     249             : {
     250       11200 :   pari_sp av = avma;
     251             :   long l;
     252       11200 :   GEN W = cgetg_copy(V, &l);
     253       11200 :   if (l <= 2) return 1;
     254       11102 :   return gc_bool(av, vecsmall_is1to1spec(V+1,l,W+1));
     255             : }
     256             : 
     257             : /*************************************************************************/
     258             : /**                                                                     **/
     259             : /**             Routines for handling vectors of VECSMALL               **/
     260             : /**                                                                     **/
     261             : /*************************************************************************/
     262             : 
     263             : GEN
     264           7 : vecvecsmall_sort(GEN x)
     265           7 : { return gen_sort(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     266             : GEN
     267      360255 : vecvecsmall_sort_shallow(GEN x)
     268      360255 : { return gen_sort_shallow(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     269             : 
     270             : void
     271         119 : vecvecsmall_sort_inplace(GEN x, GEN *perm)
     272         119 : { gen_sort_inplace(x, (void*)&vecsmall_lexcmp, cmp_nodata, perm); }
     273             : 
     274             : GEN
     275         462 : vecvecsmall_sort_uniq(GEN x)
     276         462 : { return gen_sort_uniq(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     277             : 
     278             : GEN
     279         441 : vecvecsmall_indexsort(GEN x)
     280         441 : { return gen_indexsort(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     281             : 
     282             : long
     283    22934359 : vecvecsmall_search(GEN x, GEN y)
     284    22934359 : { return gen_search(x,y,(void*)vecsmall_prefixcmp, cmp_nodata); }
     285             : 
     286             : /* assume x non empty */
     287             : long
     288           0 : vecvecsmall_max(GEN x)
     289             : {
     290           0 :   long i, l = lg(x), m = vecsmall_max(gel(x,1));
     291           0 :   for (i = 2; i < l; i++)
     292             :   {
     293           0 :     long t = vecsmall_max(gel(x,i));
     294           0 :     if (t > m) m = t;
     295             :   }
     296           0 :   return m;
     297             : }
     298             : 
     299             : /*************************************************************************/
     300             : /**                                                                     **/
     301             : /**                  Routines for handling permutations                 **/
     302             : /**                                                                     **/
     303             : /*************************************************************************/
     304             : 
     305             : /* Permutations may be given by
     306             :  * perm (VECSMALL): a bijection from 1...n to 1...n i-->perm[i]
     307             :  * cyc (VEC of VECSMALL): a product of disjoint cycles. */
     308             : 
     309             : /* Multiply (compose) two permutations, putting the result in the second one. */
     310             : static void
     311          21 : perm_mul_inplace2(GEN s, GEN t)
     312             : {
     313          21 :   long i, l = lg(s);
     314         525 :   for (i = 1; i < l; i++) t[i] = s[t[i]];
     315          21 : }
     316             : 
     317             : GEN
     318           0 : vecperm_extendschreier(GEN C, GEN v, long n)
     319             : {
     320           0 :   pari_sp av = avma;
     321           0 :   long mj, lv = lg(v), m = 1, mtested = 1;
     322           0 :   GEN bit = const_vecsmall(n, 0);
     323           0 :   GEN cy = cgetg(n+1, t_VECSMALL);
     324           0 :   GEN sh = const_vec(n, gen_0);
     325           0 :   for(mj=1; mj<=n; mj++)
     326             :   {
     327           0 :     if (isintzero(gel(C,mj))) continue;
     328           0 :     gel(sh,mj) = gcopy(gel(C,mj));
     329           0 :     if (bit[mj]) continue;
     330           0 :     cy[m++] = mj;
     331           0 :     bit[mj] = 1;
     332             :     for(;;)
     333           0 :     {
     334           0 :       long o, mold = m;
     335           0 :       for (o = 1; o < lv; o++)
     336             :       {
     337           0 :         GEN vo = gel(v,o);
     338             :         long p;
     339           0 :         for (p = mtested; p < mold; p++) /* m increases! */
     340             :         {
     341           0 :           long j = vo[ cy[p] ];
     342           0 :           if (!bit[j])
     343             :           {
     344           0 :             gel(sh,j) = perm_mul(vo, gel(sh, cy[p]));
     345           0 :             cy[m++] = j;
     346             :           }
     347           0 :           bit[j] = 1;
     348             :         }
     349             :       }
     350           0 :       mtested = mold;
     351           0 :       if (m == mold) break;
     352             :     }
     353             :   }
     354           0 :   return gerepileupto(av, sh);
     355             : }
     356             : 
     357             : /* Orbits of the subgroup generated by v on {1,..,n} */
     358             : static GEN
     359     1136173 : vecperm_orbits_i(GEN v, long n)
     360             : {
     361     1136173 :   long mj = 1, lv = lg(v), k, l;
     362     1136173 :   GEN cycle = cgetg(n+1, t_VEC), bit = const_vecsmall(n, 0);
     363     7318055 :   for (k = 1, l = 1; k <= n;)
     364             :   {
     365     6181823 :     pari_sp ltop = avma;
     366     6181823 :     long m = 1;
     367     6181823 :     GEN cy = cgetg(n+1, t_VECSMALL);
     368     7500343 :     for (  ; bit[mj]; mj++) /*empty*/;
     369     6181689 :     k++; cy[m++] = mj;
     370     6181689 :     bit[mj++] = 1;
     371             :     for(;;)
     372     2289851 :     {
     373     8471540 :       long o, mold = m;
     374    16957354 :       for (o = 1; o < lv; o++)
     375             :       {
     376     8485814 :         GEN vo = gel(v,o);
     377             :         long p;
     378    27778675 :         for (p = 1; p < m; p++) /* m increases! */
     379             :         {
     380    19292861 :           long j = vo[ cy[p] ];
     381    19292861 :           if (!bit[j]) cy[m++] = j;
     382    19292861 :           bit[j] = 1;
     383             :         }
     384             :       }
     385     8471540 :       if (m == mold) break;
     386     2289851 :       k += m - mold;
     387             :     }
     388     6181689 :     setlg(cy, m);
     389     6181641 :     gel(cycle,l++) = gerepileuptoleaf(ltop, cy);
     390             :   }
     391     1136232 :   setlg(cycle, l); return cycle;
     392             : }
     393             : /* memory clean version */
     394             : GEN
     395        4732 : vecperm_orbits(GEN v, long n)
     396             : {
     397        4732 :   pari_sp av = avma;
     398        4732 :   return gerepilecopy(av, vecperm_orbits_i(v, n));
     399             : }
     400             : 
     401             : static int
     402        2667 : isperm(GEN v)
     403             : {
     404        2667 :   pari_sp av = avma;
     405        2667 :   long i, n = lg(v)-1;
     406             :   GEN w;
     407        2667 :   if (typ(v) != t_VECSMALL) return 0;
     408        2667 :   w = zero_zv(n);
     409       26411 :   for (i=1; i<=n; i++)
     410             :   {
     411       23779 :     long d = v[i];
     412       23779 :     if (d < 1 || d > n || w[d]) return gc_bool(av,0);
     413       23744 :     w[d] = 1;
     414             :   }
     415        2632 :   return gc_bool(av,1);
     416             : }
     417             : 
     418             : /* Compute the cyclic decomposition of a permutation */
     419             : GEN
     420       13370 : perm_cycles(GEN v)
     421             : {
     422       13370 :   pari_sp av = avma;
     423       13370 :   return gerepilecopy(av, vecperm_orbits_i(mkvec(v), lg(v)-1));
     424             : }
     425             : 
     426             : GEN
     427         259 : permcycles(GEN v)
     428             : {
     429         259 :   if (!isperm(v)) pari_err_TYPE("permcycles",v);
     430         252 :   return perm_cycles(v);
     431             : }
     432             : 
     433             : /* Output the order of p */
     434             : ulong
     435      433190 : perm_orderu(GEN v)
     436             : {
     437      433190 :   pari_sp av = avma;
     438      433190 :   GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1);
     439             :   long i, d;
     440     3087808 :   for(i=1, d=1; i<lg(c); i++) d = ulcm(d, lg(gel(c,i))-1);
     441      433198 :   return gc_ulong(av,d);
     442             : }
     443             : 
     444             : static GEN
     445        2002 : _domul(void *data, GEN x, GEN y)
     446             : {
     447        2002 :   GEN (*mul)(GEN,GEN)=(GEN (*)(GEN,GEN)) data;
     448        2002 :   return mul(x,y);
     449             : }
     450             : 
     451             : /* Output the order of p */
     452             : GEN
     453         427 : perm_order(GEN v)
     454             : {
     455         427 :   pari_sp av = avma;
     456         427 :   GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1);
     457         427 :   long i, l = lg(c);
     458         427 :   GEN V = cgetg(l, t_VEC);
     459        2856 :   for (i = 1; i < l; i++)
     460        2429 :     gel(V,i) = utoi(lg(gel(c,i))-1);
     461         427 :   return gerepileuptoint(av, gen_product(V, (void *)lcmii, _domul));
     462             : }
     463             : 
     464             : GEN
     465         434 : permorder(GEN v)
     466             : {
     467         434 :   if (!isperm(v)) pari_err_TYPE("permorder",v);
     468         427 :   return perm_order(v);
     469             : }
     470             : 
     471             : /* sign of a permutation */
     472             : long
     473      684489 : perm_sign(GEN v)
     474             : {
     475      684489 :   pari_sp av = avma;
     476      684489 :   GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1);
     477      684493 :   long i, l = lg(c), s = 1;
     478     4153529 :   for (i = 1; i < l; i++)
     479     3469040 :     if (odd(lg(gel(c, i)))) s = -s;
     480      684489 :   return gc_long(av,s);
     481             : }
     482             : 
     483             : long
     484         273 : permsign(GEN v)
     485             : {
     486         273 :   if (!isperm(v)) pari_err_TYPE("permsign",v);
     487         259 :   return perm_sign(v);
     488             : }
     489             : 
     490             : GEN
     491        5915 : Z_to_perm(long n, GEN x)
     492             : {
     493             :   pari_sp av;
     494             :   ulong i, r;
     495        5915 :   GEN v = cgetg(n+1, t_VECSMALL);
     496        5915 :   if (n==0) return v;
     497        5908 :   uel(v,n) = 1; av = avma;
     498        5908 :   if (signe(x) <= 0) x = modii(x, mpfact(n));
     499       27146 :   for (r=n-1; r>=1; r--)
     500             :   {
     501             :     ulong a;
     502       21238 :     x = absdiviu_rem(x, n+1-r, &a);
     503       71687 :     for (i=r+1; i<=(ulong)n; i++)
     504       50449 :       if (uel(v,i) > a) uel(v,i)++;
     505       21238 :     uel(v,r) = a+1;
     506             :   }
     507        5908 :   set_avma(av); return v;
     508             : }
     509             : GEN
     510        5915 : numtoperm(long n, GEN x)
     511             : {
     512        5915 :   if (n < 0) pari_err_DOMAIN("numtoperm", "n", "<", gen_0, stoi(n));
     513        5915 :   if (typ(x) != t_INT) pari_err_TYPE("numtoperm",x);
     514        5915 :   return Z_to_perm(n, x);
     515             : }
     516             : 
     517             : /* destroys v */
     518             : static GEN
     519        1701 : perm_to_Z_inplace(GEN v)
     520             : {
     521        1701 :   long l = lg(v), i, r;
     522        1701 :   GEN x = gen_0;
     523        1701 :   if (!isperm(v)) return NULL;
     524       10143 :   for (i = 1; i < l; i++)
     525             :   {
     526        8449 :     long vi = v[i];
     527        8449 :     if (vi <= 0) return NULL;
     528        8449 :     x = i==1 ? utoi(vi-1): addiu(muliu(x,l-i), vi-1);
     529       25396 :     for (r = i+1; r < l; r++)
     530       16947 :       if (v[r] > vi) v[r]--;
     531             :   }
     532        1694 :   return x;
     533             : }
     534             : GEN
     535        1680 : perm_to_Z(GEN v)
     536             : {
     537        1680 :   pari_sp av = avma;
     538        1680 :   GEN x = perm_to_Z_inplace(leafcopy(v));
     539        1680 :   if (!x) pari_err_TYPE("permtonum",v);
     540        1680 :   return gerepileuptoint(av, x);
     541             : }
     542             : GEN
     543        1708 : permtonum(GEN p)
     544             : {
     545        1708 :   pari_sp av = avma;
     546             :   GEN v, x;
     547        1708 :   switch(typ(p))
     548             :   {
     549        1680 :     case t_VECSMALL: return perm_to_Z(p);
     550          21 :     case t_VEC: case t_COL:
     551          21 :       if (RgV_is_ZV(p)) { v = ZV_to_zv(p); break; }
     552           7 :     default: pari_err_TYPE("permtonum",p);
     553             :       return NULL;/*LCOV_EXCL_LINE*/
     554             :   }
     555          21 :   x = perm_to_Z_inplace(v);
     556          21 :   if (!x) pari_err_TYPE("permtonum",p);
     557          14 :   return gerepileuptoint(av, x);
     558             : }
     559             : 
     560             : GEN
     561        7336 : cyc_pow(GEN cyc, long exp)
     562             : {
     563             :   long i, j, k, l, r;
     564             :   GEN c;
     565       22239 :   for (r = j = 1; j < lg(cyc); j++)
     566             :   {
     567       14903 :     long n = lg(gel(cyc,j)) - 1;
     568       14903 :     r += cgcd(n, exp);
     569             :   }
     570        7336 :   c = cgetg(r, t_VEC);
     571       22239 :   for (r = j = 1; j < lg(cyc); j++)
     572             :   {
     573       14903 :     GEN v = gel(cyc,j);
     574       14903 :     long n = lg(v) - 1, e = umodsu(exp,n), g = (long)ugcd(n, e), m = n / g;
     575       31724 :     for (i = 0; i < g; i++)
     576             :     {
     577       16821 :       GEN p = cgetg(m+1, t_VECSMALL);
     578       16821 :       gel(c,r++) = p;
     579       54824 :       for (k = 1, l = i; k <= m; k++)
     580             :       {
     581       38003 :         p[k] = v[l+1];
     582       38003 :         l += e; if (l >= n) l -= n;
     583             :       }
     584             :     }
     585             :   }
     586        7336 :   return c;
     587             : }
     588             : 
     589             : /* Compute the power of a permutation given by product of cycles
     590             :  * Ouput a perm, not a cyc */
     591             : GEN
     592           0 : cyc_pow_perm(GEN cyc, long exp)
     593             : {
     594             :   long e, j, k, l, n;
     595             :   GEN p;
     596           0 :   for (n = 0, j = 1; j < lg(cyc); j++) n += lg(gel(cyc,j))-1;
     597           0 :   p = cgetg(n + 1, t_VECSMALL);
     598           0 :   for (j = 1; j < lg(cyc); j++)
     599             :   {
     600           0 :     GEN v = gel(cyc,j);
     601           0 :     n = lg(v) - 1; e = umodsu(exp, n);
     602           0 :     for (k = 1, l = e; k <= n; k++)
     603             :     {
     604           0 :       p[v[k]] = v[l+1];
     605           0 :       if (++l == n) l = 0;
     606             :     }
     607             :   }
     608           0 :   return p;
     609             : }
     610             : 
     611             : GEN
     612          49 : perm_pow(GEN perm, GEN exp)
     613             : {
     614          49 :   long i, r = lg(perm)-1;
     615          49 :   GEN p = zero_zv(r);
     616          49 :   pari_sp av = avma;
     617          49 :   GEN v = cgetg(r+1, t_VECSMALL);
     618         168 :   for (i=1; i<=r; i++)
     619             :   {
     620             :     long e, n, k, l;
     621         119 :     if (p[i]) continue;
     622          49 :     v[1] = i;
     623         119 :     for (n=1, k=perm[i]; k!=i; k=perm[k], n++) v[n+1] = k;
     624          49 :     e = umodiu(exp, n);
     625         168 :     for (k = 1, l = e; k <= n; k++)
     626             :     {
     627         119 :       p[v[k]] = v[l+1];
     628         119 :       if (++l == n) l = 0;
     629             :     }
     630             :   }
     631          49 :   set_avma(av); return p;
     632             : }
     633             : 
     634             : GEN
     635       18529 : perm_powu(GEN perm, ulong exp)
     636             : {
     637       18529 :   ulong i, r = lg(perm)-1;
     638       18529 :   GEN p = zero_zv(r);
     639       18529 :   pari_sp av = avma;
     640       18529 :   GEN v = cgetg(r+1, t_VECSMALL);
     641      245686 :   for (i=1; i<=r; i++)
     642             :   {
     643             :     ulong e, n, k, l;
     644      227157 :     if (p[i]) continue;
     645       84406 :     v[1] = i;
     646      227157 :     for (n=1, k=perm[i]; k!=i; k=perm[k], n++) v[n+1] = k;
     647       84406 :     e = exp % n;
     648      311563 :     for (k = 1, l = e; k <= n; k++)
     649             :     {
     650      227157 :       p[v[k]] = v[l+1];
     651      227157 :       if (++l == n) l = 0;
     652             :     }
     653             :   }
     654       18529 :   set_avma(av); return p;
     655             : }
     656             : 
     657             : GEN
     658          21 : perm_to_GAP(GEN p)
     659             : {
     660          21 :   pari_sp ltop=avma;
     661             :   GEN gap;
     662             :   GEN x;
     663             :   long i;
     664          21 :   long nb, c=0;
     665             :   char *s;
     666             :   long sz;
     667          21 :   long lp=lg(p)-1;
     668          21 :   if (typ(p) != t_VECSMALL)  pari_err_TYPE("perm_to_GAP",p);
     669          21 :   x = perm_cycles(p);
     670          21 :   sz = (long) ((bfffo(lp)+1) * LOG10_2 + 1);
     671             :   /*Dry run*/
     672         133 :   for (i = 1, nb = 1; i < lg(x); ++i)
     673             :   {
     674         112 :     GEN z = gel(x,i);
     675         112 :     long lz = lg(z)-1;
     676         112 :     nb += 1+lz*(sz+2);
     677             :   }
     678          21 :   nb++;
     679             :   /*Real run*/
     680          21 :   gap = cgetg(nchar2nlong(nb) + 1, t_STR);
     681          21 :   s = GSTR(gap);
     682         133 :   for (i = 1; i < lg(x); ++i)
     683             :   {
     684             :     long j;
     685         112 :     GEN z = gel(x,i);
     686         112 :     if (lg(z) > 2)
     687             :     {
     688         112 :       s[c++] = '(';
     689         364 :       for (j = 1; j < lg(z); ++j)
     690             :       {
     691         252 :         if (j > 1)
     692             :         {
     693         140 :           s[c++] = ','; s[c++] = ' ';
     694             :         }
     695         252 :         sprintf(s+c,"%ld",z[j]);
     696         567 :         while(s[c++]) /* empty */;
     697         252 :         c--;
     698             :       }
     699         112 :       s[c++] = ')';
     700             :     }
     701             :   }
     702          21 :   if (!c) { s[c++]='('; s[c++]=')'; }
     703          21 :   s[c] = '\0';
     704          21 :   return gerepileupto(ltop,gap);
     705             : }
     706             : 
     707             : int
     708      572495 : perm_commute(GEN s, GEN t)
     709             : {
     710      572495 :   long i, l = lg(t);
     711    40373487 :   for (i = 1; i < l; i++)
     712    39820382 :     if (t[ s[i] ] != s[ t[i] ]) return 0;
     713      553105 :   return 1;
     714             : }
     715             : 
     716             : /*************************************************************************/
     717             : /**                                                                     **/
     718             : /**                  Routines for handling groups                       **/
     719             : /**                                                                     **/
     720             : /*************************************************************************/
     721             : /* A Group is a t_VEC [gen,orders]
     722             :  * gen (vecvecsmall): list of generators given by permutations
     723             :  * orders (vecsmall): relatives orders of generators. */
     724      935901 : INLINE GEN grp_get_gen(GEN G) { return gel(G,1); }
     725     1584943 : INLINE GEN grp_get_ord(GEN G) { return gel(G,2); }
     726             : 
     727             : /* A Quotient Group is a t_VEC [gen,coset]
     728             :  * gen (vecvecsmall): coset generators
     729             :  * coset (vecsmall): gen[coset[p[1]]] generate the p-coset.
     730             :  */
     731      140951 : INLINE GEN quo_get_gen(GEN C) { return gel(C,1); }
     732       29708 : INLINE GEN quo_get_coset(GEN C) { return gel(C,2); }
     733             : 
     734             : static GEN
     735       52346 : trivialsubgroups(void)
     736       52346 : { GEN L = cgetg(2, t_VEC); gel(L,1) = trivialgroup(); return L; }
     737             : 
     738             : /* Compute the order of p modulo the group given by a set */
     739             : long
     740      220115 : perm_relorder(GEN p, GEN set)
     741             : {
     742      220115 :   pari_sp ltop = avma;
     743      220115 :   long n = 1, q = p[1];
     744      653877 :   while (!F2v_coeff(set,q)) { q = p[q]; n++; }
     745      220115 :   return gc_long(ltop,n);
     746             : }
     747             : 
     748             : GEN
     749       13048 : perm_generate(GEN S, GEN H, long o)
     750             : {
     751       13048 :   long i, n = lg(H)-1;
     752       13048 :   GEN L = cgetg(n*o + 1, t_VEC);
     753       45829 :   for(i=1; i<=n;     i++) gel(L,i) = vecsmall_copy(gel(H,i));
     754       50617 :   for(   ; i <= n*o; i++) gel(L,i) = perm_mul(gel(L,i-n), S);
     755       13048 :   return L;
     756             : }
     757             : 
     758             : /*Return the order (cardinality) of a group */
     759             : long
     760      705340 : group_order(GEN G)
     761             : {
     762      705340 :   return zv_prod(grp_get_ord(G));
     763             : }
     764             : 
     765             : /* G being a subgroup of S_n, output n */
     766             : long
     767       26628 : group_domain(GEN G)
     768             : {
     769       26628 :   GEN gen = grp_get_gen(G);
     770       26628 :   if (lg(gen) < 2) pari_err_DOMAIN("group_domain", "#G", "=", gen_1,G);
     771       26628 :   return lg(gel(gen,1)) - 1;
     772             : }
     773             : 
     774             : /*Left coset of g mod G: gG*/
     775             : GEN
     776      301231 : group_leftcoset(GEN G, GEN g)
     777             : {
     778      301231 :   GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     779      301231 :   GEN res = cgetg(group_order(G)+1, t_VEC);
     780             :   long i, j, k;
     781      301230 :   gel(res,1) = vecsmall_copy(g);
     782      301233 :   k = 1;
     783      553857 :   for (i = 1; i < lg(gen); i++)
     784             :   {
     785      252628 :     long c = k * (ord[i] - 1);
     786      694757 :     for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i));
     787             :   }
     788      301229 :   return res;
     789             : }
     790             : /*Right coset of g mod G: Gg*/
     791             : GEN
     792      179451 : group_rightcoset(GEN G, GEN g)
     793             : {
     794      179451 :   GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     795      179451 :   GEN res = cgetg(group_order(G)+1, t_VEC);
     796             :   long i, j, k;
     797      179450 :   gel(res,1) = vecsmall_copy(g);
     798      179450 :   k = 1;
     799      309965 :   for (i = 1; i < lg(gen); i++)
     800             :   {
     801      130515 :     long c = k * (ord[i] - 1);
     802      410807 :     for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(gen,i), gel(res,j));
     803             :   }
     804      179450 :   return res;
     805             : }
     806             : /*Elements of a group from the generators, cf group_leftcoset*/
     807             : GEN
     808      140713 : group_elts(GEN G, long n)
     809             : {
     810      140713 :   GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     811      140713 :   GEN res = cgetg(group_order(G)+1, t_VEC);
     812             :   long i, j, k;
     813      140713 :   gel(res,1) = identity_perm(n);
     814      140713 :   k = 1;
     815      285179 :   for (i = 1; i < lg(gen); i++)
     816             :   {
     817      144465 :     long c = k * (ord[i] - 1);
     818             :     /* j = 1, use res[1] = identity */
     819      144465 :     gel(res,++k) = vecsmall_copy(gel(gen,i));
     820      384125 :     for (j = 2; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i));
     821             :   }
     822      140714 :   return res;
     823             : }
     824             : 
     825             : GEN
     826       14448 : groupelts_conj_set(GEN elts, GEN p)
     827             : {
     828       14448 :   long i, j, l = lg(elts), n = lg(p)-1;
     829       14448 :   GEN res = zero_F2v(n);
     830      241465 :   for(j = 1; j < n; j++)
     831      241465 :     if (p[j]==1) break;
     832      101136 :   for(i = 1; i < l; i++)
     833       86688 :     F2v_set(res, p[mael(elts,i,j)]);
     834       14448 :   return res;
     835             : }
     836             : 
     837             : GEN
     838       28014 : groupelts_set(GEN elts, long n)
     839             : {
     840       28014 :   GEN res = zero_F2v(n);
     841       28014 :   long i, l = lg(elts);
     842      137410 :   for(i=1; i<l; i++)
     843      109396 :     F2v_set(res,mael(elts,i,1));
     844       28014 :   return res;
     845             : }
     846             : 
     847             : /*Elements of a group from the generators, returned as a set (bitmap)*/
     848             : GEN
     849       90671 : group_set(GEN G, long n)
     850             : {
     851       90671 :   GEN res = zero_F2v(n);
     852       90671 :   pari_sp av = avma;
     853       90671 :   GEN elts = group_elts(G, n);
     854       90671 :   long i, l = lg(elts);
     855      284214 :   for(i=1; i<l; i++)
     856      193543 :     F2v_set(res,mael(elts,i,1));
     857       90671 :   set_avma(av);
     858       90671 :   return res;
     859             : }
     860             : 
     861             : static int
     862       17353 : sgcmp(GEN a, GEN b) { return vecsmall_lexcmp(gel(a,1),gel(b,1)); }
     863             : 
     864             : GEN
     865         497 : subgroups_tableset(GEN S, long n)
     866             : {
     867         497 :   long i, l = lg(S);
     868         497 :   GEN  v = cgetg(l, t_VEC);
     869        5411 :   for(i=1; i<l; i++)
     870        4914 :     gel(v,i) = mkvec2(group_set(gel(S,i), n), mkvecsmall(i));
     871         497 :   gen_sort_inplace(v,(void*)sgcmp,cmp_nodata, NULL);
     872         497 :   return v;
     873             : }
     874             : 
     875             : long
     876        2002 : tableset_find_index(GEN tbl, GEN set)
     877             : {
     878        2002 :   long i = tablesearch(tbl,mkvec2(set,mkvecsmall(0)),sgcmp);
     879        2002 :   if (!i) return 0;
     880        2002 :   return mael3(tbl,i,2,1);
     881             : }
     882             : 
     883             : GEN
     884       52367 : trivialgroup(void) { retmkvec2(cgetg(1,t_VEC), cgetg(1,t_VECSMALL)); }
     885             : 
     886             : /*Cyclic group generated by g of order s*/
     887             : GEN
     888       26656 : cyclicgroup(GEN g, long s)
     889       26656 : { retmkvec2(mkvec( vecsmall_copy(g) ), mkvecsmall(s)); }
     890             : 
     891             : /*Return the group generated by g1,g2 of relative orders s1,s2*/
     892             : GEN
     893        1085 : dicyclicgroup(GEN g1, GEN g2, long s1, long s2)
     894        1085 : { retmkvec2( mkvec2(vecsmall_copy(g1), vecsmall_copy(g2)),
     895             :              mkvecsmall2(s1, s2) ); }
     896             : 
     897             : /* return the quotient map G --> G/H */
     898             : /*The ouput is [gen,hash]*/
     899             : /* gen (vecvecsmall): coset generators
     900             :  * coset (vecsmall): vecsmall of coset number) */
     901             : GEN
     902       11522 : groupelts_quotient(GEN elt, GEN H)
     903             : {
     904       11522 :   pari_sp ltop = avma;
     905             :   GEN  p2, p3;
     906       11522 :   long i, j, a = 1;
     907       11522 :   long n = lg(gel(elt,1))-1, o = group_order(H);
     908             :   GEN  el;
     909       11522 :   long le = lg(elt)-1;
     910       11522 :   GEN used = zero_F2v(le+1);
     911       11522 :   long l = le/o;
     912       11522 :   p2 = cgetg(l+1, t_VEC);
     913       11522 :   p3 = zero_zv(n);
     914       11522 :   el = zero_zv(n);
     915      148722 :   for (i = 1; i<=le; i++)
     916      137200 :     el[mael(elt,i,1)]=i;
     917       68075 :   for (i = 1; i <= l; ++i)
     918             :   {
     919             :     GEN V;
     920      150003 :     while(F2v_coeff(used,a)) a++;
     921       56560 :     V = group_leftcoset(H,gel(elt,a));
     922       56560 :     gel(p2,i) = gel(V,1);
     923      193655 :     for(j=1;j<lg(V);j++)
     924             :     {
     925      137102 :       long b = el[mael(V,j,1)];
     926      137102 :       if (b==0) pari_err_IMPL("group_quotient for a non-WSS group");
     927      137095 :       F2v_set(used,b);
     928             :     }
     929      193641 :     for (j = 1; j <= o; j++)
     930      137088 :       p3[mael(V, j, 1)] = i;
     931             :   }
     932       11515 :   return gerepilecopy(ltop,mkvec2(p2,p3));
     933             : }
     934             : 
     935             : GEN
     936       10157 : group_quotient(GEN G, GEN H)
     937             : {
     938       10157 :   return groupelts_quotient(group_elts(G, group_domain(G)), H);
     939             : }
     940             : 
     941             : /*Compute the image of a permutation by a quotient map.*/
     942             : GEN
     943       29708 : quotient_perm(GEN C, GEN p)
     944             : {
     945       29708 :   GEN gen = quo_get_gen(C);
     946       29708 :   GEN coset = quo_get_coset(C);
     947       29708 :   long j, l = lg(gen);
     948       29708 :   GEN p3 = cgetg(l, t_VECSMALL);
     949      282163 :   for (j = 1; j < l; ++j)
     950             :   {
     951      252455 :     p3[j] = coset[p[mael(gen,j,1)]];
     952      252455 :     if (p3[j]==0) pari_err_IMPL("quotient_perm for a non-WSS group");
     953             :   }
     954       29708 :   return p3;
     955             : }
     956             : 
     957             : /* H is a subgroup of G, C is the quotient map G --> G/H
     958             :  *
     959             :  * Lift a subgroup S of G/H to a subgroup of G containing H */
     960             : GEN
     961       50547 : quotient_subgroup_lift(GEN C, GEN H, GEN S)
     962             : {
     963       50547 :   GEN genH = grp_get_gen(H);
     964       50547 :   GEN genS = grp_get_gen(S);
     965       50547 :   GEN genC = quo_get_gen(C);
     966       50547 :   long l1 = lg(genH)-1;
     967       50547 :   long l2 = lg(genS)-1, j;
     968       50547 :   GEN p1 = cgetg(3, t_VEC), L = cgetg(l1+l2+1, t_VEC);
     969      101262 :   for (j = 1; j <= l1; ++j) gel(L,j) = gel(genH,j);
     970      117719 :   for (j = 1; j <= l2; ++j) gel(L,l1+j) = gel(genC, mael(genS,j,1));
     971       50547 :   gel(p1,1) = L;
     972       50547 :   gel(p1,2) = vecsmall_concat(grp_get_ord(H), grp_get_ord(S));
     973       50547 :   return p1;
     974             : }
     975             : 
     976             : /* Let G a group and C a quotient map G --> G/H
     977             :  * Assume H is normal, return the group G/H */
     978             : GEN
     979       10150 : quotient_group(GEN C, GEN G)
     980             : {
     981       10150 :   pari_sp ltop = avma;
     982             :   GEN Qgen, Qord, Qelt, Qset, Q;
     983       10150 :   GEN Cgen = quo_get_gen(C);
     984       10150 :   GEN Ggen = grp_get_gen(G);
     985       10150 :   long i,j, n = lg(Cgen)-1, l = lg(Ggen);
     986       10150 :   Qord = cgetg(l, t_VECSMALL);
     987       10150 :   Qgen = cgetg(l, t_VEC);
     988       10150 :   Qelt = mkvec(identity_perm(n));
     989       10150 :   Qset = groupelts_set(Qelt, n);
     990       31052 :   for (i = 1, j = 1; i < l; ++i)
     991             :   {
     992       20902 :     GEN  g = quotient_perm(C, gel(Ggen,i));
     993       20902 :     long o = perm_relorder(g, Qset);
     994       20902 :     gel(Qgen,j) = g;
     995       20902 :     Qord[j] = o;
     996       20902 :     if (o != 1)
     997             :     {
     998       13048 :       Qelt = perm_generate(g, Qelt, o);
     999       13048 :       Qset = groupelts_set(Qelt, n);
    1000       13048 :       j++;
    1001             :     }
    1002             :   }
    1003       10150 :   setlg(Qgen,j);
    1004       10150 :   setlg(Qord,j); Q = mkvec2(Qgen, Qord);
    1005       10150 :   return gerepilecopy(ltop,Q);
    1006             : }
    1007             : 
    1008             : GEN
    1009        1365 : quotient_groupelts(GEN C)
    1010             : {
    1011        1365 :   GEN G = quo_get_gen(C);
    1012        1365 :   long i, l = lg(G);
    1013        1365 :   GEN Q = cgetg(l, t_VEC);
    1014       10171 :   for (i = 1; i < l; ++i)
    1015        8806 :     gel(Q,i) = quotient_perm(C, gel(G,i));
    1016        1365 :   return Q;
    1017             : }
    1018             : 
    1019             : /* Return 1 if g normalizes N, 0 otherwise */
    1020             : long
    1021      179451 : group_perm_normalize(GEN N, GEN g)
    1022             : {
    1023      179451 :   pari_sp ltop = avma;
    1024      179451 :   long r = gequal(vecvecsmall_sort_shallow(group_leftcoset(N, g)),
    1025             :                   vecvecsmall_sort_shallow(group_rightcoset(N, g)));
    1026      179451 :   return gc_long(ltop, r);
    1027             : }
    1028             : 
    1029             : /* L is a list of subgroups, C is a coset and r a relative order.*/
    1030             : static GEN
    1031       65219 : liftlistsubgroups(GEN L, GEN C, long r)
    1032             : {
    1033       65219 :   pari_sp ltop = avma;
    1034       65219 :   long c = lg(C)-1, l = lg(L)-1, n = lg(gel(C,1))-1, i, k;
    1035             :   GEN R;
    1036       65219 :   if (!l) return cgetg(1,t_VEC);
    1037       58527 :   R = cgetg(l*c+1, t_VEC);
    1038      142968 :   for (i = 1, k = 1; i <= l; ++i)
    1039             :   {
    1040       84441 :     GEN S = gel(L,i), Selt = group_set(S,n);
    1041       84441 :     GEN gen = grp_get_gen(S);
    1042       84441 :     GEN ord = grp_get_ord(S);
    1043             :     long j;
    1044      279202 :     for (j = 1; j <= c; ++j)
    1045             :     {
    1046      194761 :       GEN p = gel(C,j);
    1047      194761 :       if (perm_relorder(p, Selt) == r && group_perm_normalize(S, p))
    1048      108731 :         gel(R,k++) = mkvec2(vec_append(gen, p),
    1049             :                             vecsmall_append(ord, r));
    1050             :     }
    1051             :   }
    1052       58527 :   setlg(R, k);
    1053       58527 :   return gerepilecopy(ltop, R);
    1054             : }
    1055             : 
    1056             : /* H is a normal subgroup, C is the quotient map G -->G/H,
    1057             :  * S is a subgroup of G/H, and G is embedded in Sym(l)
    1058             :  * Return all the subgroups K of G such that
    1059             :  * S= K mod H and K inter H={1} */
    1060             : static GEN
    1061       49182 : liftsubgroup(GEN C, GEN H, GEN S)
    1062             : {
    1063       49182 :   pari_sp ltop = avma;
    1064       49182 :   GEN V = trivialsubgroups();
    1065       49182 :   GEN Sgen = grp_get_gen(S);
    1066       49182 :   GEN Sord = grp_get_ord(S);
    1067       49182 :   GEN Cgen = quo_get_gen(C);
    1068       49182 :   long n = lg(Sgen), i;
    1069      114401 :   for (i = 1; i < n; ++i)
    1070             :   { /*loop over generators of S*/
    1071       65219 :     GEN W = group_leftcoset(H, gel(Cgen, mael(Sgen, i, 1)));
    1072       65219 :     V = liftlistsubgroups(V, W, Sord[i]);
    1073             :   }
    1074       49182 :   return gerepilecopy(ltop,V);
    1075             : }
    1076             : 
    1077             : /* 1:A4, 2:S4, 3:F36, 0: other */
    1078             : long
    1079        9982 : group_isA4S4(GEN G)
    1080             : {
    1081        9982 :   GEN elt = grp_get_gen(G);
    1082        9982 :   GEN ord = grp_get_ord(G);
    1083        9982 :   long n = lg(ord);
    1084        9982 :   if (n != 4 && n != 5) return 0;
    1085        2219 :   if (n==4 && ord[1]==3 && ord[2]==3 && ord[3]==4)
    1086             :   {
    1087             :     long i;
    1088           7 :     GEN p = gel(elt,1), q = gel(elt,2), r = gel(elt,3);
    1089         259 :     for(i=1; i<=36; i++)
    1090         252 :       if (p[r[i]]!=r[q[i]]) return 0;
    1091           7 :     return 3;
    1092             :   }
    1093        2212 :   if (ord[1]!=2 || ord[2]!=2 || ord[3]!=3) return 0;
    1094          42 :   if (perm_commute(gel(elt,1),gel(elt,3))) return 0;
    1095          42 :   if (n==4) return 1;
    1096          21 :   if (ord[4]!=2) return 0;
    1097          21 :   if (perm_commute(gel(elt,3),gel(elt,4))) return 0;
    1098          21 :   return 2;
    1099             : }
    1100             : /* compute all the subgroups of a group G */
    1101             : GEN
    1102       13146 : group_subgroups(GEN G)
    1103             : {
    1104       13146 :   pari_sp ltop = avma;
    1105             :   GEN p1, H, C, Q, M, sg1, sg2, sg3;
    1106       13146 :   GEN gen = grp_get_gen(G);
    1107       13146 :   GEN ord = grp_get_ord(G);
    1108       13146 :   long lM, i, j, n = lg(gen);
    1109             :   long t;
    1110       13146 :   if (n == 1) return trivialsubgroups();
    1111        9982 :   t = group_isA4S4(G);
    1112        9982 :   if (t == 3)
    1113             :   {
    1114           7 :     GEN H = mkvec2(mkvec3(gel(gen,1), gel(gen,2), perm_sqr(gel(gen,3))),
    1115             :                    mkvecsmall3(3, 3, 2));
    1116           7 :     GEN S = group_subgroups(H);
    1117           7 :     GEN V = cgetg(11,t_VEC);
    1118           7 :     gel(V,1) = cyclicgroup(gel(gen,3),4);
    1119          63 :     for (i=2; i<10; i++)
    1120          56 :       gel(V,i) = cyclicgroup(perm_mul(gmael3(V,i-1,1,1),gel(gen,i%3==1 ? 2:1)),4);
    1121           7 :     gel(V,10) = G;
    1122           7 :     return gerepilecopy(ltop,shallowconcat(S,V));
    1123             :   }
    1124        9975 :   else if (t)
    1125             :   {
    1126          42 :     GEN s = gel(gen,1);       /*s = (1,2)(3,4) */
    1127          42 :     GEN t = gel(gen,2);       /*t = (1,3)(2,4) */
    1128          42 :     GEN st = perm_mul(s, t); /*st = (1,4)(2,3) */
    1129          42 :     H = dicyclicgroup(s, t, 2, 2);
    1130             :     /* sg3 is the list of subgroups intersecting only partially with H*/
    1131          42 :     sg3 = cgetg((n==4)?4: 10, t_VEC);
    1132          42 :     gel(sg3,1) = cyclicgroup(s, 2);
    1133          42 :     gel(sg3,2) = cyclicgroup(t, 2);
    1134          42 :     gel(sg3,3) = cyclicgroup(st, 2);
    1135          42 :     if (n==5)
    1136             :     {
    1137          21 :       GEN u = gel(gen,3);
    1138          21 :       GEN v = gel(gen,4), w, u2;
    1139          21 :       if (zv_equal(perm_conj(u,s), t)) /*u=(2,3,4)*/
    1140          21 :         u2 = perm_sqr(u);
    1141             :       else
    1142             :       {
    1143           0 :         u2 = u;
    1144           0 :         u = perm_sqr(u);
    1145             :       }
    1146          21 :       if (perm_orderu(v)==2)
    1147             :       {
    1148          21 :         if (!perm_commute(s,v)) /*v=(1,2)*/
    1149             :         {
    1150           0 :           v = perm_conj(u,v);
    1151           0 :           if (!perm_commute(s,v)) v = perm_conj(u,v);
    1152             :         }
    1153          21 :         w = perm_mul(v,t); /*w=(1,4,2,3)*/
    1154             :       }
    1155             :       else
    1156             :       {
    1157           0 :         w = v;
    1158           0 :         if (!zv_equal(perm_sqr(w), s)) /*w=(1,4,2,3)*/
    1159             :         {
    1160           0 :           w = perm_conj(u,w);
    1161           0 :           if (!zv_equal(perm_sqr(w), s)) w = perm_conj(u,w);
    1162             :         }
    1163           0 :         v = perm_mul(w,t); /*v=(1,2)*/
    1164             :       }
    1165          21 :       gel(sg3,4) = dicyclicgroup(s,v,2,2);
    1166          21 :       gel(sg3,5) = dicyclicgroup(t,perm_conj(u,v),2,2);
    1167          21 :       gel(sg3,6) = dicyclicgroup(st,perm_conj(u2,v),2,2);
    1168          21 :       gel(sg3,7) = dicyclicgroup(s,w,2,2);
    1169          21 :       gel(sg3,8) = dicyclicgroup(t,perm_conj(u,w),2,2);
    1170          21 :       gel(sg3,9) = dicyclicgroup(st,perm_conj(u2,w),2,2);
    1171             :     }
    1172             :   }
    1173             :   else
    1174             :   {
    1175        9933 :     ulong osig = mael(factoru(ord[1]), 1, 1);
    1176        9933 :     GEN sig = perm_powu(gel(gen,1), ord[1]/osig);
    1177        9933 :     H = cyclicgroup(sig,osig);
    1178        9933 :     sg3 = NULL;
    1179             :   }
    1180        9975 :   C = group_quotient(G,H);
    1181        9968 :   Q = quotient_group(C,G);
    1182        9968 :   M = group_subgroups(Q); lM = lg(M);
    1183             :   /* sg1 is the list of subgroups containing H*/
    1184        9961 :   sg1 = cgetg(lM, t_VEC);
    1185       59143 :   for (i = 1; i < lM; ++i) gel(sg1,i) = quotient_subgroup_lift(C,H,gel(M,i));
    1186             :   /*sg2 is a list of lists of subgroups not intersecting with H*/
    1187        9961 :   sg2 = cgetg(lM, t_VEC);
    1188             :   /* Loop over all subgroups of G/H */
    1189       59143 :   for (j = 1; j < lM; ++j) gel(sg2,j) = liftsubgroup(C, H, gel(M,j));
    1190        9961 :   p1 = gconcat(sg1, shallowconcat1(sg2));
    1191        9961 :   if (sg3)
    1192             :   {
    1193          42 :     p1 = gconcat(p1, sg3);
    1194          42 :     if (n==5) /*ensure that the D4 subgroups of S4 are in supersolvable format*/
    1195          84 :       for(j = 3; j <= 5; j++)
    1196             :       {
    1197          63 :         GEN c = gmael(p1,j,1);
    1198          63 :         if (!perm_commute(gel(c,1),gel(c,3)))
    1199             :         {
    1200          42 :           if (perm_commute(gel(c,2),gel(c,3))) { swap(gel(c,1), gel(c,2)); }
    1201             :           else
    1202          21 :             perm_mul_inplace2(gel(c,2), gel(c,1));
    1203             :         }
    1204             :       }
    1205             :   }
    1206        9961 :   return gerepileupto(ltop,p1);
    1207             : }
    1208             : 
    1209             : /*return 1 if G is abelian, else 0*/
    1210             : long
    1211        9177 : group_isabelian(GEN G)
    1212             : {
    1213        9177 :   GEN g = grp_get_gen(G);
    1214        9177 :   long i, j, n = lg(g);
    1215       13097 :   for(i=2; i<n; i++)
    1216       13034 :     for(j=1; j<i; j++)
    1217        9114 :       if (!perm_commute(gel(g,i), gel(g,j))) return 0;
    1218        4235 :   return 1;
    1219             : }
    1220             : 
    1221             : /*If G is abelian, return its HNF matrix*/
    1222             : GEN
    1223         385 : group_abelianHNF(GEN G, GEN S)
    1224             : {
    1225         385 :   GEN M, g = grp_get_gen(G), o = grp_get_ord(G);
    1226         385 :   long i, j, k, n = lg(g);
    1227         385 :   if (!group_isabelian(G)) return NULL;
    1228         315 :   if (n==1) return cgetg(1,t_MAT);
    1229         301 :   if (!S) S = group_elts(G, group_domain(G));
    1230         301 :   M = cgetg(n,t_MAT);
    1231         980 :   for(i=1; i<n; i++)
    1232             :   {
    1233         679 :     GEN P, C = cgetg(n,t_COL);
    1234         679 :     pari_sp av = avma;
    1235         679 :     gel(M,i) = C;
    1236         679 :     P = perm_inv(perm_powu(gel(g,i), o[i]));
    1237         959 :     for(j=1; j<lg(S); j++)
    1238         959 :       if (zv_equal(P, gel(S,j))) break;
    1239         679 :     set_avma(av);
    1240         679 :     if (j==lg(S)) pari_err_BUG("galoisisabelian [inconsistent group]");
    1241         679 :     j--;
    1242        1218 :     for(k=1; k<i; k++)
    1243             :     {
    1244         539 :       long q = j / o[k];
    1245         539 :       gel(C,k) = stoi(j - q*o[k]);
    1246         539 :       j = q;
    1247             :     }
    1248         679 :     gel(C,k) = stoi(o[i]);
    1249        1218 :     for (k++; k<n; k++) gel(C,k) = gen_0;
    1250             :   }
    1251         301 :   return M;
    1252             : }
    1253             : 
    1254             : /*If G is abelian, return its abstract SNF matrix*/
    1255             : GEN
    1256         336 : group_abelianSNF(GEN G, GEN L)
    1257             : {
    1258         336 :   pari_sp ltop = avma;
    1259         336 :   GEN H = group_abelianHNF(G,L);
    1260         336 :   if (!H) return NULL;
    1261         266 :   return gerepileupto(ltop, smithclean( ZM_snf(H) ));
    1262             : }
    1263             : 
    1264             : GEN
    1265         455 : abelian_group(GEN v)
    1266             : {
    1267         455 :   long card = zv_prod(v), i, d = 1, l = lg(v);
    1268         455 :   GEN G = cgetg(3,t_VEC), gen = cgetg(l,t_VEC);
    1269         455 :   gel(G,1) = gen;
    1270         455 :   gel(G,2) = vecsmall_copy(v);
    1271         959 :   for(i=1; i<l; i++)
    1272             :   {
    1273         504 :     GEN p = cgetg(card+1, t_VECSMALL);
    1274         504 :     long o = v[i], u = d*(o-1), j, k, l;
    1275         504 :     gel(gen, i) = p;
    1276             :     /* The following loop is over-optimized. Remember that I wrote it for
    1277             :      * testpermutation. Something has survived... BA */
    1278        1148 :     for(j=1;j<=card;)
    1279             :     {
    1280        2380 :       for(k=1;k<o;k++)
    1281        4599 :         for(l=1;l<=d; l++,j++) p[j] = j+d;
    1282        2107 :       for (l=1; l<=d; l++,j++) p[j] = j-u;
    1283             :     }
    1284         504 :     d += u;
    1285             :   }
    1286         455 :   return G;
    1287             : }
    1288             : 
    1289             : static long
    1290       13783 : groupelts_subgroup_isnormal(GEN G, GEN H)
    1291             : {
    1292       13783 :   long i, n = lg(G);
    1293       61530 :   for(i = 1; i < n; i++)
    1294       60102 :     if (!group_perm_normalize(H, gel(G,i))) return 0;
    1295        1428 :   return 1;
    1296             : }
    1297             : 
    1298             : /*return 1 if H is a normal subgroup of G*/
    1299             : long
    1300         336 : group_subgroup_isnormal(GEN G, GEN H)
    1301             : {
    1302         336 :   if (lg(grp_get_gen(H)) > 1 && group_domain(G) != group_domain(H))
    1303           0 :     pari_err_DOMAIN("group_subgroup_isnormal","domain(H)","!=",
    1304             :                     strtoGENstr("domain(G)"), H);
    1305         336 :   return groupelts_subgroup_isnormal(grp_get_gen(G), H);
    1306             : }
    1307             : 
    1308             : static GEN
    1309        4816 : group_subgroup_kernel_set(GEN G, GEN H)
    1310             : {
    1311             :   pari_sp av;
    1312        4816 :   GEN g = grp_get_gen(G);
    1313        4816 :   long i, n = lg(g);
    1314             :   GEN S, elts;
    1315        4816 :   long d = group_domain(G);
    1316        4816 :   if (lg(grp_get_gen(H)) > 1 && group_domain(G) != group_domain(H))
    1317           0 :     pari_err_DOMAIN("group_subgroup_isnormal","domain(H)","!=",
    1318             :                     strtoGENstr("domain(G)"), H);
    1319        4816 :   elts = group_elts(H,d);
    1320        4816 :   S = groupelts_set(elts, d);
    1321        4816 :   av = avma;
    1322       19264 :   for(i=1; i<n; i++)
    1323             :   {
    1324       14448 :     F2v_and_inplace(S, groupelts_conj_set(elts,gel(g,i)));
    1325       14448 :     set_avma(av);
    1326             :   }
    1327        4816 :   return S;
    1328             : }
    1329             : 
    1330             : int
    1331        4816 : group_subgroup_is_faithful(GEN G, GEN H)
    1332             : {
    1333        4816 :   pari_sp av = avma;
    1334        4816 :   GEN K = group_subgroup_kernel_set(G,H);
    1335        4816 :   F2v_clear(K,1);
    1336        4816 :   return gc_long(av, F2v_equal0(K));
    1337             : }
    1338             : 
    1339             : long
    1340           0 : groupelts_exponent(GEN elts)
    1341             : {
    1342           0 :   long i, n = lg(elts)-1, expo = 1;
    1343           0 :   for(i=1; i<=n; i++) expo = ulcm(expo, perm_orderu(gel(elts,i)));
    1344           0 :   return expo;
    1345             : }
    1346             : 
    1347             : GEN
    1348         700 : groupelts_center(GEN S)
    1349             : {
    1350         700 :   pari_sp ltop = avma;
    1351         700 :   long i, j, n = lg(S)-1, l = n;
    1352         700 :   GEN V, elts = zero_F2v(n+1);
    1353       25732 :   for(i=1; i<=n; i++)
    1354             :   {
    1355       25032 :     if (F2v_coeff(elts,i)) { l--;  continue; }
    1356      573384 :     for(j=1; j<=n; j++)
    1357      563192 :       if (!perm_commute(gel(S,i),gel(S,j)))
    1358             :       {
    1359       14322 :         F2v_set(elts,i);
    1360       14322 :         F2v_set(elts,j); l--; break;
    1361             :       }
    1362             :   }
    1363         700 :   V = cgetg(l+1,t_VEC);
    1364       25732 :   for (i=1, j=1; i<=n ;i++)
    1365       25032 :     if (!F2v_coeff(elts,i)) gel(V,j++) = vecsmall_copy(gel(S,i));
    1366         700 :   return gerepileupto(ltop,V);
    1367             : }
    1368             : 
    1369             : GEN
    1370        4270 : groupelts_conjclasses(GEN elts, long *pnbcl)
    1371             : {
    1372        4270 :   long i, j, cl = 0, n = lg(elts)-1;
    1373        4270 :   GEN c = const_vecsmall(n,0);
    1374        4270 :   pari_sp av = avma;
    1375       52850 :   for (i=1; i<=n; i++)
    1376             :   {
    1377       48580 :     GEN g = gel(elts,i);
    1378       48580 :     if (c[i]) continue;
    1379       34965 :     c[i] = ++cl;
    1380      486871 :     for(j=1; j<=n; j++)
    1381      451906 :       if (j != i)
    1382             :       {
    1383      416941 :         GEN h = perm_conj(gel(elts,j), g);
    1384      416941 :         long i2 = gen_search(elts,h,(void*)&vecsmall_lexcmp,&cmp_nodata);
    1385      416941 :         c[i2] = cl; set_avma(av);
    1386             :       }
    1387             :   }
    1388        4270 :   if (pnbcl) *pnbcl = cl;
    1389        4270 :   return c;
    1390             : }
    1391             : 
    1392             : GEN
    1393        4270 : conjclasses_repr(GEN conj, long nb)
    1394             : {
    1395        4270 :   long i, l = lg(conj);
    1396        4270 :   GEN e = const_vecsmall(nb, 0);
    1397       52850 :   for(i=1; i<l; i++)
    1398             :   {
    1399       48580 :     long ci = conj[i];
    1400       48580 :     if (!e[ci]) e[ci] = i;
    1401             :   }
    1402        4270 :   return e;
    1403             : }
    1404             : 
    1405             : /* elts of G sorted wrt vecsmall_lexcmp order: g in G is determined by g[1]
    1406             :  * so sort by increasing g[1] */
    1407             : static GEN
    1408        3885 : galois_elts_sorted(GEN gal)
    1409             : {
    1410             :   long i, l;
    1411        3885 :   GEN elts = gal_get_group(gal), v = cgetg_copy(elts, &l);
    1412       43141 :   for (i = 1; i < l; i++) { GEN g = gel(elts,i); gel(v, g[1]) = g; }
    1413        3885 :   return v;
    1414             : }
    1415             : GEN
    1416        4291 : group_to_cc(GEN G)
    1417             : {
    1418        4291 :   GEN elts = checkgroupelts(G), z = cgetg(5,t_VEC);
    1419        4270 :   long n, flag = 1;
    1420        4270 :   if (typ(gel(G,1)) == t_POL)
    1421        3885 :     elts = galois_elts_sorted(G); /* galoisinit */
    1422             :   else
    1423             :   {
    1424         385 :     long i, l = lg(elts);
    1425         385 :     elts = gen_sort_shallow(elts,(void*)vecsmall_lexcmp,cmp_nodata);
    1426        5824 :     for (i = 1; i < l; i++)
    1427        5586 :       if (gel(elts,i)[1] != i) { flag = 0; break; }
    1428             :   }
    1429        4270 :   gel(z,1) = elts;
    1430        4270 :   gel(z,2) = groupelts_conjclasses(elts,&n);
    1431        4270 :   gel(z,3) = conjclasses_repr(gel(z,2),n);
    1432        4270 :   gel(z,4) = utoi(flag); return z;
    1433             : }
    1434             : 
    1435             : /* S a list of generators */
    1436             : GEN
    1437           0 : groupelts_abelian_group(GEN S)
    1438             : {
    1439           0 :   pari_sp ltop = avma;
    1440             :   GEN Qgen, Qord, Qelt;
    1441           0 :   long i, j, n = lg(gel(S,1))-1, l = lg(S);
    1442           0 :   Qord = cgetg(l, t_VECSMALL);
    1443           0 :   Qgen = cgetg(l, t_VEC);
    1444           0 :   Qelt = mkvec(identity_perm(n));
    1445           0 :   for (i = 1, j = 1; i < l; ++i)
    1446             :   {
    1447           0 :     GEN  g = gel(S,i);
    1448           0 :     long o = perm_relorder(g, groupelts_set(Qelt, n));
    1449           0 :     gel(Qgen,j) = g;
    1450           0 :     Qord[j] = o;
    1451           0 :     if (o != 1) { Qelt = perm_generate(g, Qelt, o); j++; }
    1452             :   }
    1453           0 :   setlg(Qgen,j);
    1454           0 :   setlg(Qord,j);
    1455           0 :   return gerepilecopy(ltop, mkvec2(Qgen, Qord));
    1456             : }
    1457             : 
    1458             : GEN
    1459          14 : group_export_GAP(GEN G)
    1460             : {
    1461          14 :   pari_sp av = avma;
    1462          14 :   GEN s, comma, g = grp_get_gen(G);
    1463          14 :   long i, k, l = lg(g);
    1464          14 :   if (l == 1) return strtoGENstr("Group(())");
    1465           7 :   s = cgetg(2*l, t_VEC);
    1466           7 :   comma = strtoGENstr(", ");
    1467           7 :   gel(s,1) = strtoGENstr("Group(");
    1468          28 :   for (i=1, k=2; i < l; ++i)
    1469             :   {
    1470          21 :     if (i > 1) gel(s,k++) = comma;
    1471          21 :     gel(s,k++) = perm_to_GAP(gel(g,i));
    1472             :   }
    1473           7 :   gel(s,k++) = strtoGENstr(")");
    1474           7 :   return gerepilecopy(av, shallowconcat1(s));
    1475             : }
    1476             : 
    1477             : GEN
    1478          14 : group_export_MAGMA(GEN G)
    1479             : {
    1480          14 :   pari_sp av = avma;
    1481          14 :   GEN s, comma, g = grp_get_gen(G);
    1482          14 :   long i, k, l = lg(g);
    1483          14 :   if (l == 1) return strtoGENstr("PermutationGroup<1|>");
    1484           7 :   s = cgetg(2*l, t_VEC);
    1485           7 :   comma = strtoGENstr(", ");
    1486           7 :   gel(s,1) = gsprintf("PermutationGroup<%ld|",group_domain(G));
    1487          28 :   for (i=1, k=2; i < l; ++i)
    1488             :   {
    1489          21 :     if (i > 1) gel(s,k++) = comma;
    1490          21 :     gel(s,k++) = GENtoGENstr( vecsmall_to_vec(gel(g,i)) );
    1491             :   }
    1492           7 :   gel(s,k++) = strtoGENstr(">");
    1493           7 :   return gerepilecopy(av, shallowconcat1(s));
    1494             : }
    1495             : 
    1496             : GEN
    1497          28 : group_export(GEN G, long format)
    1498             : {
    1499          28 :   switch(format)
    1500             :   {
    1501          14 :   case 0: return group_export_GAP(G);
    1502          14 :   case 1: return group_export_MAGMA(G);
    1503             :   }
    1504           0 :   pari_err_FLAG("galoisexport");
    1505           0 :   return NULL; /*-Wall*/
    1506             : }
    1507             : 
    1508             : static GEN
    1509        3010 : groupelts_cyclic_subgroups(GEN G)
    1510             : {
    1511        3010 :   pari_sp av = avma;
    1512        3010 :   long i, j, n = lg(G)-1;
    1513             :   GEN elts, f, gen, ord;
    1514        3010 :   if (n==1) return cgetg(1,t_VEC);
    1515        3010 :   elts = zero_F2v(lg(gel(G,1))-1);
    1516        3010 :   gen = cgetg(n+1, t_VECSMALL);
    1517        3010 :   ord = cgetg(n+1, t_VECSMALL);
    1518       48958 :   for (i=1, j=1; i<=n; i++)
    1519             :   {
    1520       45948 :     long k = 1, o, c = 0;
    1521       45948 :     GEN p = gel(G, i);
    1522       45948 :     if (F2v_coeff(elts, p[1])) continue;
    1523       33439 :     o = perm_orderu(p);
    1524       33439 :     gen[j] = i; ord[j] = o; j++;
    1525             :     do
    1526             :     {
    1527       90748 :       if (cgcd(o, ++c)==1) F2v_set(elts, p[k]);
    1528       90748 :       k = p[k];
    1529       90748 :     } while (k!=1);
    1530             :   }
    1531        3010 :   setlg(gen, j);
    1532        3010 :   setlg(ord, j);
    1533        3010 :   f = vecsmall_indexsort(ord);
    1534        3010 :   return gerepilecopy(av, mkvec2(vecpermute(gen, f), vecpermute(ord, f)));
    1535             : }
    1536             : 
    1537             : GEN
    1538        3017 : groupelts_to_group(GEN G)
    1539             : {
    1540        3017 :   pari_sp av = avma;
    1541             :   GEN L, cyc, ord;
    1542        3017 :   long i, l, n = lg(G)-1;
    1543        3017 :   if (n==1) return trivialgroup();
    1544        3003 :   L = groupelts_cyclic_subgroups(G);
    1545        3003 :   cyc = gel(L,1); ord = gel(L,2);
    1546        3003 :   l = lg(cyc);
    1547       15085 :   for (i = l-1; i >= 2; i--)
    1548             :   {
    1549       14455 :     GEN p = gel(G,cyc[i]);
    1550       14455 :     long o = ord[i];
    1551       14455 :     GEN H = cyclicgroup(p, o);
    1552       14455 :     if (o == n) return gerepileupto(av, H);
    1553       13447 :     if (groupelts_subgroup_isnormal(G, H))
    1554             :     {
    1555        1365 :       GEN C = groupelts_quotient(G, H);
    1556        1365 :       GEN Q = quotient_groupelts(C);
    1557        1365 :       GEN R = groupelts_to_group(Q);
    1558        1365 :       if (!R) return gc_NULL(av);
    1559        1365 :       return gerepilecopy(av, quotient_subgroup_lift(C, H, R));
    1560             :     }
    1561             :   }
    1562         630 :   if (n==12 && l==9 && ord[2]==2 && ord[3]==2 && ord[5]==3)
    1563         532 :     return gerepilecopy(av,
    1564         266 :       mkvec2(mkvec3(gel(G,cyc[2]), gel(G,cyc[3]), gel(G,cyc[5])), mkvecsmall3(2,2,3)));
    1565         364 :   if (n==24 && l==18 && ord[11]==3 && ord[15]==4 && ord[16]==4)
    1566             :   {
    1567         350 :     GEN t21 = perm_sqr(gel(G,cyc[15]));
    1568         350 :     GEN t22 = perm_sqr(gel(G,cyc[16]));
    1569         350 :     GEN s = perm_mul(t22, gel(G,cyc[15]));
    1570         700 :     return gerepilecopy(av,
    1571         350 :       mkvec2(mkvec4(t21,t22, gel(G,cyc[11]), s), mkvecsmall4(2,2,3,2)));
    1572             :   }
    1573          14 :   if (n==36 && l==24 && ord[11]==3 && ord[15]==4)
    1574             :   {
    1575           7 :     GEN t1 = gel(G,cyc[11]), t3 = gel(G,cyc[15]);
    1576           7 :     return gerepilecopy(av,
    1577             :       mkvec2(mkvec3(perm_conj(t3, t1), t1, t3), mkvecsmall3(3,3,4)));
    1578             :   }
    1579           7 :   return gc_NULL(av);
    1580             : }
    1581             : 
    1582             : static GEN
    1583         581 : subg_get_gen(GEN subg) {  return gel(subg, 1); }
    1584             : 
    1585             : static GEN
    1586        4333 : subg_get_set(GEN subg) {  return gel(subg, 2); }
    1587             : 
    1588             : static GEN
    1589         399 : groupelt_subg_normalize(GEN elt, GEN subg, GEN cyc)
    1590             : {
    1591         399 :   GEN gen = subg_get_gen(subg), set =  subg_get_set(subg);
    1592         399 :   long i, j, u, n = lg(elt)-1, lgen = lg(gen);
    1593         399 :   GEN b = F2v_copy(cyc), res = zero_F2v(n);
    1594       24339 :   for(i = 1; i <= n; i++)
    1595             :   {
    1596             :     GEN g;
    1597       23940 :     if (!F2v_coeff(b, i)) continue;
    1598       11186 :     g = gel(elt,i);
    1599      381731 :     for(u=1; u<=n; u++)
    1600      381731 :       if (g[u]==1) break;
    1601       12159 :     for(j=1; j<lgen; j++)
    1602             :     {
    1603       11473 :       GEN h = gel(elt,gen[j]);
    1604       11473 :       if (!F2v_coeff(set,g[h[u]])) break;
    1605             :     }
    1606       11186 :     if (j < lgen) continue;
    1607         686 :     F2v_set(res,i);
    1608       41846 :     for(j=1; j <= n; j++)
    1609       41160 :       if (F2v_coeff(set, j))
    1610        2940 :         F2v_clear(b,g[gel(elt,j)[1]]);
    1611             :   }
    1612         399 :   return res;
    1613             : }
    1614             : 
    1615             : static GEN
    1616           7 : triv_subg(GEN elt)
    1617             : {
    1618           7 :   GEN v = cgetg(3, t_VEC);
    1619           7 :   gel(v,1) = cgetg(1,t_VECSMALL);
    1620           7 :   gel(v,2) = zero_F2v(lg(elt)-1);
    1621           7 :   F2v_set(gel(v,2),1);
    1622           7 :   return v;
    1623             : }
    1624             : 
    1625             : static GEN
    1626         182 : subg_extend(GEN U, long e, long o, GEN elt)
    1627             : {
    1628         182 :   long i, j, n = lg(elt)-1;
    1629         182 :   GEN g = gel(elt, e);
    1630         182 :   GEN gen = vecsmall_append(subg_get_gen(U), e);
    1631         182 :   GEN set = subg_get_set(U);
    1632         182 :   GEN Vset = zv_copy(set);
    1633       11102 :   for(i = 1; i <= n; i++)
    1634       10920 :     if (F2v_coeff(set, i))
    1635             :     {
    1636         630 :       long h = gel(elt, i)[1];
    1637        1400 :       for(j = 1; j < o; j++)
    1638             :       {
    1639         770 :         h = g[h];
    1640         770 :         F2v_set(Vset, h);
    1641             :       }
    1642             :     }
    1643         182 :   return mkvec2(gen, Vset);
    1644             : }
    1645             : 
    1646             : static GEN
    1647         217 : cyclic_subg(long e, long o, GEN elt)
    1648             : {
    1649         217 :   long j, n = lg(elt)-1, h = 1;
    1650         217 :   GEN g = gel(elt, e);
    1651         217 :   GEN gen = mkvecsmall(e);
    1652         217 :   GEN set = zero_F2v(n);
    1653         217 :   F2v_set(set,1);
    1654         630 :   for(j = 1; j < o; j++)
    1655             :   {
    1656         413 :     h = g[h];
    1657         413 :     F2v_set(set, h);
    1658             :   }
    1659         217 :   return mkvec2(gen, set);
    1660             : }
    1661             : 
    1662             : static GEN
    1663           7 : groupelts_to_regular(GEN elt)
    1664             : {
    1665           7 :   long i, j, n = lg(elt)-1;
    1666           7 :   GEN V = cgetg(n+1,t_VEC);
    1667         427 :   for (i=1; i<=n; i++)
    1668             :   {
    1669         420 :     pari_sp av = avma;
    1670         420 :     GEN g = gel(elt, i);
    1671         420 :     GEN W = cgetg(n+1,t_VEC);
    1672       25620 :     for(j=1; j<=n; j++)
    1673       25200 :       gel(W,j) = perm_mul(g, gel(elt,j));
    1674         420 :     gel(V, i) = gerepileuptoleaf(av,vecvecsmall_indexsort(W));
    1675             :   }
    1676           7 :   vecvecsmall_sort_inplace(V, NULL);
    1677           7 :   return V;
    1678             : }
    1679             : 
    1680             : static long
    1681         217 : groupelts_pow(GEN elt, long j, long n)
    1682             : {
    1683         217 :   GEN g = gel(elt,j);
    1684         217 :   long i, h = 1;
    1685         847 :   for (i=1; i<=n; i++)
    1686         630 :     h = g[h];
    1687         217 :   return h;
    1688             : }
    1689             : 
    1690             : static GEN
    1691           7 : groupelts_cyclic_primepow(GEN elt, GEN *pt_pr, GEN *pt_po)
    1692             : {
    1693           7 :   GEN R = groupelts_cyclic_subgroups(elt);
    1694           7 :   GEN gen = gel(R,1), ord = gel(R,2);
    1695           7 :   long i, n = lg(elt)-1, l = lg(gen);
    1696           7 :   GEN set = zero_F2v(n);
    1697           7 :   GEN pr  = zero_Flv(n);
    1698           7 :   GEN po  = zero_Flv(n);
    1699         231 :   for (i = 1; i < l; i++)
    1700             :   {
    1701         224 :     long h = gen[i];
    1702             :     ulong p;
    1703         224 :     if (uisprimepower(ord[i], &p))
    1704             :     {
    1705         217 :       F2v_set(set, h);
    1706         217 :       uel(pr,h) = p;
    1707         217 :       po[h] = groupelts_pow(elt, h, p);
    1708             :     }
    1709             :   }
    1710           7 :   *pt_pr = pr; *pt_po = po;
    1711           7 :   return set;
    1712             : }
    1713             : 
    1714             : static GEN
    1715           7 : all_cyclic_subg(GEN pr, GEN po, GEN elt)
    1716             : {
    1717           7 :   long i, n = lg(pr)-1, m = 0, k = 1;
    1718             :   GEN W;
    1719         427 :   for (i=1; i <= n; i++)
    1720         420 :     m += po[i]==1;
    1721           7 :   W = cgetg(m+1, t_VEC);
    1722         427 :   for (i=1; i <= n; i++)
    1723         420 :     if (po[i]==1)
    1724         217 :       gel(W, k++) = cyclic_subg(i, pr[i], elt);
    1725           7 :   return W;
    1726             : }
    1727             : 
    1728             : static GEN
    1729           7 : groupelts_subgroups_raw(GEN elts)
    1730             : {
    1731           7 :   pari_sp av = avma;
    1732           7 :   GEN elt = groupelts_to_regular(elts);
    1733           7 :   GEN pr, po, cyc = groupelts_cyclic_primepow(elt, &pr, &po);
    1734           7 :   long n = lg(elt)-1;
    1735           7 :   long i, j, nS = 1;
    1736             :   GEN S, L;
    1737           7 :   S = cgetg(1+bigomegau(n)+1, t_VEC);
    1738           7 :   gel(S, nS++) = mkvec(triv_subg(elt));
    1739           7 :   gel(S, nS++) = L = all_cyclic_subg(pr, po, elt);
    1740           7 :   if (DEBUGLEVEL) err_printf("subgroups: level %ld: %ld\n",nS,lg(L)-1);
    1741          28 :   while (lg(L) > 1)
    1742             :   {
    1743          21 :     pari_sp av2 = avma;
    1744          21 :     long nW = 1, lL = lg(L);
    1745          21 :     long ng = n;
    1746          21 :     GEN W = cgetg(1+ng, t_VEC);
    1747         420 :     for (i=1; i<lL; i++)
    1748             :     {
    1749         399 :       GEN U = gel(L, i), set = subg_get_set(U);
    1750         399 :       GEN G = groupelt_subg_normalize(elt, U, cyc);
    1751        3570 :       for (j=1; j<nW; j++)
    1752             :       {
    1753        3171 :         GEN Wj = subg_get_set(gel(W, j));
    1754        3171 :         if (F2v_subset(set, Wj))
    1755         364 :           F2v_negimply_inplace(G, Wj);
    1756             :       }
    1757       24339 :       for (j=1; j<=n; j++)
    1758       23940 :         if(F2v_coeff(G,j))
    1759             :         {
    1760         378 :           long p = pr[j];
    1761         378 :           if (F2v_coeff(set, j)) continue;
    1762         182 :           if (F2v_coeff(set, po[j]))
    1763             :           {
    1764         182 :             GEN U2 = subg_extend(U, j, p, elt);
    1765         182 :             F2v_negimply_inplace(G, subg_get_set(U2));
    1766         182 :             if (nW > ng) { ng<<=1; W = vec_lengthen(W, ng); }
    1767         182 :             gel(W, nW++) = U2;
    1768             :           }
    1769             :         }
    1770             :     }
    1771          21 :     setlg(W, nW);
    1772          21 :     if (DEBUGLEVEL) err_printf("subgroups: level %ld: %ld\n",nS,nW-1);
    1773          21 :     L = W;
    1774          21 :     if (nW > 1) gel(S, nS++) = L = gerepilecopy(av2, W);
    1775             :   }
    1776           7 :   setlg(S, nS);
    1777           7 :   return gerepilecopy(av, shallowconcat1(S));
    1778             : }
    1779             : 
    1780             : static GEN
    1781         406 : set_groupelts(GEN S, GEN x)
    1782             : {
    1783         406 :   long i, n = F2v_hamming(x), k=1, m = x[1];
    1784         406 :   GEN v = cgetg(n+1, t_VEC);
    1785       24766 :   for (i=1; i<=m; i++)
    1786       24360 :     if (F2v_coeff(x,i))
    1787        2037 :       gel(v,k++) = gel(S,i);
    1788         406 :   return v;
    1789             : }
    1790             : 
    1791             : static GEN
    1792           7 : subg_to_elts(GEN S, GEN x)
    1793         413 : { pari_APPLY_type(t_VEC, set_groupelts(S, gmael(x,i,2))); }
    1794             : 
    1795             : GEN
    1796           7 : groupelts_solvablesubgroups(GEN G)
    1797             : {
    1798           7 :   pari_sp av = avma;
    1799           7 :   GEN S = vecvecsmall_sort(checkgroupelts(G));
    1800           7 :   GEN L = groupelts_subgroups_raw(S);
    1801           7 :   return gerepilecopy(av, subg_to_elts(S, L));
    1802             : }

Generated by: LCOV version 1.13