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.18.1 lcov report (development 30733-eb2d773d38) Lines: 1025 1112 92.2 %
Date: 2026-03-03 09:24:12 Functions: 112 119 94.1 %
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        1848 : vec_isconst(GEN v)
      25             : {
      26        1848 :   long i, l = lg(v);
      27             :   GEN w;
      28        1848 :   if (l==1) return 1;
      29        1848 :   w = gel(v,1);
      30        6349 :   for(i=2; i<l; i++)
      31        5768 :     if (!gequal(gel(v,i), w)) return 0;
      32         581 :   return 1;
      33             : }
      34             : 
      35             : int
      36       17893 : vecsmall_isconst(GEN v)
      37             : {
      38       17893 :   long i, l = lg(v);
      39             :   ulong w;
      40       17893 :   if (l==1) return 1;
      41       17893 :   w = uel(v,1);
      42       30735 :   for(i=2; i<l; i++)
      43       24721 :     if (uel(v,i) != w) return 0;
      44        6014 :   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   279797544 : vecsmall_sortspec(GEN v, long n, GEN w)
      81             : {
      82   279797544 :   pari_sp ltop=avma;
      83   279797544 :   long nx=n>>1, ny=n-nx;
      84             :   long m, ix, iy;
      85             :   GEN x, y;
      86   279797544 :   if (n<=2)
      87             :   {
      88   163193220 :     if (n==1)
      89    34792610 :       w[0]=v[0];
      90   128400610 :     else if (n==2)
      91             :     {
      92   133355696 :       long v0=v[0], v1=v[1];
      93   133355696 :       if (v0<=v1) { w[0]=v0; w[1]=v1; }
      94     4213780 :       else        { w[0]=v1; w[1]=v0; }
      95             :     }
      96   163193220 :     return;
      97             :   }
      98   116604324 :   x=new_chunk(nx); y=new_chunk(ny);
      99   126034573 :   vecsmall_sortspec(v,nx,x);
     100   127616186 :   vecsmall_sortspec(v+nx,ny,y);
     101   570703974 :   for (m=0, ix=0, iy=0; ix<nx && iy<ny; )
     102   440142406 :     if (x[ix]<=y[iy])
     103   371628125 :       w[m++]=x[ix++];
     104             :     else
     105    68514281 :       w[m++]=y[iy++];
     106   133478950 :   for(;ix<nx;) w[m++]=x[ix++];
     107   487194953 :   for(;iy<ny;) w[m++]=y[iy++];
     108   130561568 :   set_avma(ltop);
     109             : }
     110             : 
     111             : static long
     112    47629987 : vecsmall_sort_max(GEN v)
     113             : {
     114    47629987 :   long i, l = lg(v), max = -1;
     115   159754173 :   for (i = 1; i < l; i++)
     116   158220143 :     if (v[i] > max) { max = v[i]; if (max >= l) return -1; }
     117    21871192 :     else if (v[i] < 0) return -1;
     118     1711991 :   return max;
     119             : }
     120             : /* assume 0 <= v[i] <= M. In place. */
     121             : void
     122     1969219 : vecsmall_counting_sort(GEN v, long M)
     123             : {
     124             :   pari_sp av;
     125             :   long i, j, k, l;
     126             :   GEN T;
     127     1969219 :   if (M == 0) return;
     128     1969219 :   av = avma; T = new_chunk(M + 1); l = lg(v);
     129     9558260 :   for (i = 0; i <= M; i++) T[i] = 0;
     130     7646940 :   for (i = 1; i < l; i++) T[v[i]]++; /* T[j] is # keys = j */
     131     9558260 :   for (j = 0, k = 1; j <= M; j++)
     132    13266768 :     for (i = 1; i <= T[j]; i++) v[k++] = j;
     133     1969218 :   set_avma(av);
     134             : }
     135             : /* not GC-clean, suitable for gc_upto */
     136             : GEN
     137       16129 : vecsmall_counting_uniq(GEN v, long M)
     138             : {
     139       16129 :   long i, k, l = lg(v);
     140             :   GEN T, U;
     141       16129 :   if (l == 1) return cgetg(1, t_VECSMALL);
     142       16129 :   if (M == 0) return mkvecsmall(0);
     143       16129 :   if (l == 2) return leafcopy(v);
     144       15989 :   U = new_chunk(M + 2);
     145       15989 :   T = U+1; /* allows to rewrite result over T also if T[0] = 1 */
     146      124283 :   for (i = 0; i <= M; i++) T[i] = 0;
     147      201788 :   for (i = 1; i < l; i++) T[v[i]] = 1;
     148      124283 :   for (i = 0, k = 1; i <= M; i++)
     149      108294 :     if (T[i]) U[k++] = i;
     150       15989 :   U[0] = evaltyp(t_VECSMALL) | _evallg(k); return U;
     151             : }
     152             : GEN
     153       12459 : vecsmall_counting_indexsort(GEN v, long M)
     154             : {
     155             :   pari_sp av;
     156       12459 :   long i, l = lg(v);
     157             :   GEN T, p;
     158       12459 :   if (M == 0 || l <= 2) return identity_zv(l - 1);
     159       12445 :   p = cgetg(l, t_VECSMALL); av = avma; T = new_chunk(M + 1);
     160       55604 :   for (i = 0; i <= M; i++) T[i] = 0;
     161    14431482 :   for (i = 1; i < l; i++) T[v[i]]++; /* T[j] is # keys = j */
     162       43159 :   for (i = 1; i <= M; i++) T[i] += T[i-1]; /* T[j] is # keys <= j */
     163    14431482 :   for (i = l-1; i > 0; i--) { p[T[v[i]]] = i; T[v[i]]--; }
     164       12445 :   return gc_const(av, p);
     165             : }
     166             : 
     167             : /* in place sort */
     168             : void
     169    52019451 : vecsmall_sort(GEN v)
     170             : {
     171    52019451 :   long n = lg(v) - 1, max;
     172    52019451 :   if (n <= 1) return;
     173    45300167 :   if ((max = vecsmall_sort_max(v)) >= 0)
     174     1969219 :     vecsmall_counting_sort(v, max);
     175             :   else
     176    43441862 :     vecsmall_sortspec(v+1, n, v+1);
     177             : }
     178             : 
     179             : /* cf gen_sortspec */
     180             : static GEN
     181     8125500 : vecsmall_indexsortspec(GEN v, long n)
     182             : {
     183             :   long nx, ny, m, ix, iy;
     184             :   GEN x, y, w;
     185     8125500 :   switch(n)
     186             :   {
     187      158712 :     case 1: return mkvecsmall(1);
     188     3680306 :     case 2: return (v[1] <= v[2])? mkvecsmall2(1,2): mkvecsmall2(2,1);
     189     1454192 :     case 3:
     190     1454192 :       if (v[1] <= v[2]) {
     191      699129 :         if (v[2] <= v[3]) return mkvecsmall3(1,2,3);
     192      208619 :         return (v[1] <= v[3])? mkvecsmall3(1,3,2)
     193      624769 :                              : mkvecsmall3(3,1,2);
     194             :       } else {
     195      755063 :         if (v[1] <= v[3]) return mkvecsmall3(2,1,3);
     196      283327 :         return (v[2] <= v[3])? mkvecsmall3(2,3,1)
     197      859122 :                              : mkvecsmall3(3,2,1);
     198             :       }
     199             :   }
     200     2832290 :   nx = n>>1; ny = n-nx;
     201     2832290 :   w = cgetg(n+1,t_VECSMALL);
     202     2832296 :   x = vecsmall_indexsortspec(v,nx);
     203     2832294 :   y = vecsmall_indexsortspec(v+nx,ny);
     204    33958840 :   for (m=1, ix=1, iy=1; ix<=nx && iy<=ny; )
     205    31126545 :     if (v[x[ix]] <= v[y[iy]+nx])
     206    15066489 :       w[m++] = x[ix++];
     207             :     else
     208    16060056 :       w[m++] = y[iy++]+nx;
     209     5398643 :   for(;ix<=nx;) w[m++] = x[ix++];
     210     5394037 :   for(;iy<=ny;) w[m++] = y[iy++]+nx;
     211     2832295 :   set_avma((pari_sp)w); return w;
     212             : }
     213             : 
     214             : /*indirect sort.*/
     215             : GEN
     216     2473436 : vecsmall_indexsort(GEN v)
     217             : {
     218     2473436 :   long n = lg(v) - 1, max;
     219     2473436 :   if (n==0) return cgetg(1, t_VECSMALL);
     220     2473373 :   if ((max = vecsmall_sort_max(v)) >= 0)
     221       12459 :     return vecsmall_counting_indexsort(v, max);
     222             :   else
     223     2460915 :     return vecsmall_indexsortspec(v,n);
     224             : }
     225             : 
     226             : /* assume V sorted */
     227             : GEN
     228       31390 : vecsmall_uniq_sorted(GEN v)
     229             : {
     230             :   long i, j, l;
     231       31390 :   GEN w = cgetg_copy(v, &l);
     232       31390 :   if (l == 1) return w;
     233       31336 :   w[1] = v[1];
     234       34309 :   for(i = j = 2; i < l; i++)
     235        2973 :     if (v[i] != w[j-1]) w[j++] = v[i];
     236       31336 :   stackdummy((pari_sp)(w + l), (pari_sp)(w + j));
     237       31336 :   setlg(w, j); return w;
     238             : }
     239             : 
     240             : GEN
     241       16488 : vecsmall_uniq(GEN v)
     242             : {
     243       16488 :   pari_sp av = avma;
     244             :   long max;
     245       16488 :   if ((max = vecsmall_sort_max(v)) >= 0)
     246       16129 :     v = vecsmall_counting_uniq(v, max);
     247             :   else
     248         359 :   { v = zv_copy(v); vecsmall_sort(v); v = vecsmall_uniq_sorted(v); }
     249       16488 :   return gc_leaf(av, v);
     250             : }
     251             : 
     252             : /* assume x sorted */
     253             : long
     254           0 : vecsmall_duplicate_sorted(GEN x)
     255             : {
     256           0 :   long i, k, l = lg(x);
     257           0 :   if (l == 1) return 0;
     258           0 :   for (k = x[1], i = 2; i < l; k = x[i++])
     259           0 :     if (x[i] == k) return i;
     260           0 :   return 0;
     261             : }
     262             : 
     263             : long
     264       20682 : vecsmall_duplicate(GEN x)
     265             : {
     266       20682 :   pari_sp av = avma;
     267       20682 :   GEN p = vecsmall_indexsort(x);
     268       20682 :   long k, i, r = 0, l = lg(x);
     269       20682 :   if (l == 1) return gc_long(av, 0);
     270       28840 :   for (k = x[p[1]], i = 2; i < l; k = x[p[i++]])
     271        8158 :     if (x[p[i]] == k) { r = p[i]; break; }
     272       20682 :   return gc_long(av, r);
     273             : }
     274             : 
     275             : static int
     276       55369 : vecsmall_is1to1spec(GEN v, long n, GEN w)
     277             : {
     278       55369 :   pari_sp av = avma;
     279       55369 :   long nx = n>>1, ny = n - nx, m, ix, iy;
     280             :   GEN x, y;
     281       55369 :   if (n <= 2)
     282             :   {
     283       33324 :     if (n == 1) w[0] = v[0];
     284       21786 :     else if (n==2)
     285             :     {
     286       21786 :       long v0 = v[0], v1 = v[1];
     287       21786 :       if (v0 == v1) return 0;
     288       21758 :       else if (v0 < v1) { w[0] = v0; w[1] = v1; }
     289        4635 :       else              { w[0] = v1; w[1] = v0; }
     290             :     }
     291       33296 :     return 1;
     292             :   }
     293       22045 :   x = new_chunk(nx); if (!vecsmall_is1to1spec(v, nx, x))    return 0;
     294       21947 :   y = new_chunk(ny); if (!vecsmall_is1to1spec(v+nx, ny, y)) return 0;
     295       85333 :   for (m = ix = iy = 0; ix < nx && iy < ny; )
     296       63484 :     if (x[ix] == y[iy]) return 0;
     297       63435 :     else if (x[ix] < y[iy])
     298       38683 :       w[m++] = x[ix++];
     299             :     else
     300       24752 :       w[m++] = y[iy++];
     301       23971 :   while (ix < nx) w[m++] = x[ix++];
     302       54431 :   while (iy < ny) w[m++] = y[iy++];
     303       21849 :   return gc_bool(av, 1);
     304             : }
     305             : 
     306             : int
     307       11503 : vecsmall_is1to1(GEN V)
     308             : {
     309       11503 :   pari_sp av = avma;
     310             :   long l;
     311       11503 :   GEN W = cgetg_copy(V, &l);
     312       11503 :   return gc_bool(av, l <= 2? 1: vecsmall_is1to1spec(V+1, l, W+1));
     313             : }
     314             : 
     315             : /*************************************************************************/
     316             : /**                                                                     **/
     317             : /**             Routines for handling vectors of VECSMALL               **/
     318             : /**                                                                     **/
     319             : /*************************************************************************/
     320             : 
     321             : GEN
     322          14 : vecvecsmall_sort(GEN x)
     323          14 : { return gen_sort(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     324             : GEN
     325      365904 : vecvecsmall_sort_shallow(GEN x)
     326      365904 : { return gen_sort_shallow(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     327             : 
     328             : void
     329         126 : vecvecsmall_sort_inplace(GEN x, GEN *perm)
     330         126 : { gen_sort_inplace(x, (void*)&vecsmall_lexcmp, cmp_nodata, perm); }
     331             : 
     332             : GEN
     333         462 : vecvecsmall_sort_uniq(GEN x)
     334         462 : { return gen_sort_uniq(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     335             : 
     336             : GEN
     337         861 : vecvecsmall_indexsort(GEN x)
     338         861 : { return gen_indexsort(x, (void*)&vecsmall_lexcmp, cmp_nodata); }
     339             : 
     340             : long
     341    22934359 : vecvecsmall_search(GEN x, GEN y)
     342    22934359 : { return gen_search(x,y,(void*)vecsmall_prefixcmp, cmp_nodata); }
     343             : 
     344             : /* assume x non empty */
     345             : long
     346           0 : vecvecsmall_max(GEN x)
     347             : {
     348           0 :   long i, l = lg(x), m = vecsmall_max(gel(x,1));
     349           0 :   for (i = 2; i < l; i++)
     350             :   {
     351           0 :     long t = vecsmall_max(gel(x,i));
     352           0 :     if (t > m) m = t;
     353             :   }
     354           0 :   return m;
     355             : }
     356             : 
     357             : /*************************************************************************/
     358             : /**                                                                     **/
     359             : /**                  Routines for handling permutations                 **/
     360             : /**                                                                     **/
     361             : /*************************************************************************/
     362             : 
     363             : /* Permutations may be given by
     364             :  * perm (VECSMALL): a bijection from 1...n to 1...n i-->perm[i]
     365             :  * cyc (VEC of VECSMALL): a product of disjoint cycles. */
     366             : 
     367             : /* Multiply (compose) two permutations, putting the result in the second one. */
     368             : static void
     369          21 : perm_mul_inplace2(GEN s, GEN t)
     370             : {
     371          21 :   long i, l = lg(s);
     372         525 :   for (i = 1; i < l; i++) t[i] = s[t[i]];
     373          21 : }
     374             : 
     375             : GEN
     376           0 : vecperm_extendschreier(GEN C, GEN v, long n)
     377             : {
     378           0 :   pari_sp av = avma;
     379           0 :   long mj, lv = lg(v), m = 1, mtested = 1;
     380           0 :   GEN bit = const_vecsmall(n, 0);
     381           0 :   GEN cy = cgetg(n+1, t_VECSMALL);
     382           0 :   GEN sh = const_vec(n, gen_0);
     383           0 :   for(mj=1; mj<=n; mj++)
     384             :   {
     385           0 :     if (isintzero(gel(C,mj))) continue;
     386           0 :     gel(sh,mj) = gcopy(gel(C,mj));
     387           0 :     if (bit[mj]) continue;
     388           0 :     cy[m++] = mj;
     389           0 :     bit[mj] = 1;
     390             :     for(;;)
     391           0 :     {
     392           0 :       long o, mold = m;
     393           0 :       for (o = 1; o < lv; o++)
     394             :       {
     395           0 :         GEN vo = gel(v,o);
     396             :         long p;
     397           0 :         for (p = mtested; p < mold; p++) /* m increases! */
     398             :         {
     399           0 :           long j = vo[ cy[p] ];
     400           0 :           if (!bit[j])
     401             :           {
     402           0 :             gel(sh,j) = perm_mul(vo, gel(sh, cy[p]));
     403           0 :             cy[m++] = j;
     404             :           }
     405           0 :           bit[j] = 1;
     406             :         }
     407             :       }
     408           0 :       mtested = mold;
     409           0 :       if (m == mold) break;
     410             :     }
     411             :   }
     412           0 :   return gc_upto(av, sh);
     413             : }
     414             : 
     415             : /* Orbits of the subgroup generated by v on {1,..,n} */
     416             : static GEN
     417      455372 : vecperm_orbits_i(GEN v, long n)
     418             : {
     419      455372 :   long mj = 1, lv = lg(v), k, l;
     420      455372 :   GEN cycle = cgetg(n+1, t_VEC), bit = const_vecsmall(n, 0);
     421     3248149 :   for (k = 1, l = 1; k <= n;)
     422             :   {
     423     2792751 :     pari_sp ltop = avma;
     424     2792751 :     long m = 1;
     425     2792751 :     GEN cy = cgetg(n+1, t_VECSMALL);
     426     3995203 :     for (  ; bit[mj]; mj++) /*empty*/;
     427     2792711 :     k++; cy[m++] = mj;
     428     2792711 :     bit[mj++] = 1;
     429             :     for(;;)
     430     2010753 :     {
     431     4803464 :       long o, mold = m;
     432     9620986 :       for (o = 1; o < lv; o++)
     433             :       {
     434     4817522 :         GEN vo = gel(v,o);
     435             :         long p;
     436    19642861 :         for (p = 1; p < m; p++) /* m increases! */
     437             :         {
     438    14825339 :           long j = vo[ cy[p] ];
     439    14825339 :           if (!bit[j]) cy[m++] = j;
     440    14825339 :           bit[j] = 1;
     441             :         }
     442             :       }
     443     4803464 :       if (m == mold) break;
     444     2010753 :       k += m - mold;
     445             :     }
     446     2792711 :     setlg(cy, m);
     447     2792742 :     gel(cycle,l++) = gc_leaf(ltop, cy);
     448             :   }
     449      455398 :   setlg(cycle, l); return cycle;
     450             : }
     451             : /* memory clean version */
     452             : GEN
     453        4893 : vecperm_orbits(GEN v, long n)
     454             : {
     455        4893 :   pari_sp av = avma;
     456        4893 :   return gc_GEN(av, vecperm_orbits_i(v, n));
     457             : }
     458             : 
     459             : static int
     460        2667 : isperm(GEN v)
     461             : {
     462        2667 :   pari_sp av = avma;
     463        2667 :   long i, n = lg(v)-1;
     464             :   GEN w;
     465        2667 :   if (typ(v) != t_VECSMALL) return 0;
     466        2667 :   w = zero_zv(n);
     467       26411 :   for (i=1; i<=n; i++)
     468             :   {
     469       23779 :     long d = v[i];
     470       23779 :     if (d < 1 || d > n || w[d]) return gc_bool(av,0);
     471       23744 :     w[d] = 1;
     472             :   }
     473        2632 :   return gc_bool(av,1);
     474             : }
     475             : 
     476             : /* Compute the cyclic decomposition of a permutation */
     477             : GEN
     478       13647 : perm_cycles(GEN v)
     479             : {
     480       13647 :   pari_sp av = avma;
     481       13647 :   return gc_GEN(av, vecperm_orbits_i(mkvec(v), lg(v)-1));
     482             : }
     483             : 
     484             : GEN
     485         259 : permcycles(GEN v)
     486             : {
     487         259 :   if (!isperm(v)) pari_err_TYPE("permcycles",v);
     488         252 :   return perm_cycles(v);
     489             : }
     490             : 
     491             : /* Output the order of p */
     492             : ulong
     493      436404 : perm_orderu(GEN v)
     494             : {
     495      436404 :   pari_sp av = avma;
     496      436404 :   GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1);
     497             :   long i, d;
     498     3169418 :   for(i=1, d=1; i<lg(c); i++) d = ulcm(d, lg(gel(c,i))-1);
     499      436436 :   return gc_ulong(av,d);
     500             : }
     501             : 
     502             : static GEN
     503        2002 : _domul(void *data, GEN x, GEN y)
     504             : {
     505        2002 :   GEN (*mul)(GEN,GEN)=(GEN (*)(GEN,GEN)) data;
     506        2002 :   return mul(x,y);
     507             : }
     508             : 
     509             : /* Output the order of p */
     510             : GEN
     511         427 : perm_order(GEN v)
     512             : {
     513         427 :   pari_sp av = avma;
     514         427 :   GEN c = vecperm_orbits_i(mkvec(v), lg(v)-1);
     515         427 :   long i, l = lg(c);
     516         427 :   GEN V = cgetg(l, t_VEC);
     517        2856 :   for (i = 1; i < l; i++)
     518        2429 :     gel(V,i) = utoi(lg(gel(c,i))-1);
     519         427 :   return gc_INT(av, gen_product(V, (void *)lcmii, _domul));
     520             : }
     521             : 
     522             : GEN
     523         434 : permorder(GEN v)
     524             : {
     525         434 :   if (!isperm(v)) pari_err_TYPE("permorder",v);
     526         427 :   return perm_order(v);
     527             : }
     528             : 
     529             : /* sign of a permutation */
     530             : long
     531      964948 : perm_sign(GEN v)
     532             : {
     533      964948 :   pari_sp av = avma;
     534      964948 :   long n = lg(v), s = 1;
     535      964948 :   GEN w = perm_inv(v);
     536      964964 :   v = vecsmall_copy(v); /* Following lines update v and w in place */
     537     5299316 :   while (--n > 1)
     538             :   { /* At this stage, v[1..n] and w[1..n] are inverse of each other.
     539             :      * Indices > n are implicitly fixed points, not updated */
     540     4334351 :     long i = v[n];
     541     4334351 :     if (i != n)
     542             :     { /* apply transposition tau_{i,n} to v and w; n becomes a fixed point */
     543      651648 :       long j = w[n];
     544      651648 :       v[j] = i;
     545      651648 :       w[i] = j;
     546      651648 :       s = -s;
     547             :     }
     548             :   }
     549      964965 :   return gc_long(av,s);
     550             : }
     551             : 
     552             : long
     553         273 : permsign(GEN v)
     554             : {
     555         273 :   if (!isperm(v)) pari_err_TYPE("permsign",v);
     556         259 :   return perm_sign(v);
     557             : }
     558             : 
     559             : GEN
     560        5915 : Z_to_perm(long n, GEN x)
     561             : {
     562             :   pari_sp av;
     563             :   ulong i, r;
     564        5915 :   GEN v = cgetg(n+1, t_VECSMALL);
     565        5915 :   if (n==0) return v;
     566        5908 :   uel(v,n) = 1; av = avma;
     567        5908 :   if (signe(x) <= 0) x = modii(x, mpfact(n));
     568       27146 :   for (r=n-1; r>=1; r--)
     569             :   {
     570             :     ulong a;
     571       21238 :     x = absdiviu_rem(x, n+1-r, &a);
     572       71687 :     for (i=r+1; i<=(ulong)n; i++)
     573       50449 :       if (uel(v,i) > a) uel(v,i)++;
     574       21238 :     uel(v,r) = a+1;
     575             :   }
     576        5908 :   return gc_const(av, v);
     577             : }
     578             : GEN
     579        5915 : numtoperm(long n, GEN x)
     580             : {
     581        5915 :   if (n < 0) pari_err_DOMAIN("numtoperm", "n", "<", gen_0, stoi(n));
     582        5915 :   if (typ(x) != t_INT) pari_err_TYPE("numtoperm",x);
     583        5915 :   return Z_to_perm(n, x);
     584             : }
     585             : 
     586             : /* destroys v */
     587             : static GEN
     588        1701 : perm_to_Z_inplace(GEN v)
     589             : {
     590        1701 :   long l = lg(v), i, r;
     591        1701 :   GEN x = gen_0;
     592        1701 :   if (!isperm(v)) return NULL;
     593       10143 :   for (i = 1; i < l; i++)
     594             :   {
     595        8449 :     long vi = v[i];
     596        8449 :     if (vi <= 0) return NULL;
     597        8449 :     x = i==1 ? utoi(vi-1): addiu(muliu(x,l-i), vi-1);
     598       25396 :     for (r = i+1; r < l; r++)
     599       16947 :       if (v[r] > vi) v[r]--;
     600             :   }
     601        1694 :   return x;
     602             : }
     603             : GEN
     604        1680 : perm_to_Z(GEN v)
     605             : {
     606        1680 :   pari_sp av = avma;
     607        1680 :   GEN x = perm_to_Z_inplace(leafcopy(v));
     608        1680 :   if (!x) pari_err_TYPE("permtonum",v);
     609        1680 :   return gc_INT(av, x);
     610             : }
     611             : GEN
     612        1708 : permtonum(GEN p)
     613             : {
     614        1708 :   pari_sp av = avma;
     615             :   GEN v, x;
     616        1708 :   switch(typ(p))
     617             :   {
     618        1680 :     case t_VECSMALL: return perm_to_Z(p);
     619          21 :     case t_VEC: case t_COL:
     620          21 :       if (RgV_is_ZV(p)) { v = ZV_to_zv(p); break; }
     621           7 :     default: pari_err_TYPE("permtonum",p);
     622             :       return NULL;/*LCOV_EXCL_LINE*/
     623             :   }
     624          21 :   x = perm_to_Z_inplace(v);
     625          21 :   if (!x) pari_err_TYPE("permtonum",p);
     626          14 :   return gc_INT(av, x);
     627             : }
     628             : 
     629             : GEN
     630        7485 : cyc_pow(GEN cyc, long exp)
     631             : {
     632             :   long i, j, k, l, r;
     633             :   GEN c;
     634       22537 :   for (r = j = 1; j < lg(cyc); j++)
     635             :   {
     636       15052 :     long n = lg(gel(cyc,j)) - 1;
     637       15052 :     r += cgcd(n, exp);
     638             :   }
     639        7485 :   c = cgetg(r, t_VEC);
     640       22537 :   for (r = j = 1; j < lg(cyc); j++)
     641             :   {
     642       15052 :     GEN v = gel(cyc,j);
     643       15052 :     long n = lg(v) - 1, e = umodsu(exp,n), g = (long)ugcd(n, e), m = n / g;
     644       32022 :     for (i = 0; i < g; i++)
     645             :     {
     646       16970 :       GEN p = cgetg(m+1, t_VECSMALL);
     647       16970 :       gel(c,r++) = p;
     648       55271 :       for (k = 1, l = i; k <= m; k++)
     649             :       {
     650       38301 :         p[k] = v[l+1];
     651       38301 :         l += e; if (l >= n) l -= n;
     652             :       }
     653             :     }
     654             :   }
     655        7485 :   return c;
     656             : }
     657             : 
     658             : /* Compute the power of a permutation given by product of cycles
     659             :  * Ouput a perm, not a cyc */
     660             : GEN
     661           0 : cyc_pow_perm(GEN cyc, long exp)
     662             : {
     663             :   long e, j, k, l, n;
     664             :   GEN p;
     665           0 :   for (n = 0, j = 1; j < lg(cyc); j++) n += lg(gel(cyc,j))-1;
     666           0 :   p = cgetg(n + 1, t_VECSMALL);
     667           0 :   for (j = 1; j < lg(cyc); j++)
     668             :   {
     669           0 :     GEN v = gel(cyc,j);
     670           0 :     n = lg(v) - 1; e = umodsu(exp, n);
     671           0 :     for (k = 1, l = e; k <= n; k++)
     672             :     {
     673           0 :       p[v[k]] = v[l+1];
     674           0 :       if (++l == n) l = 0;
     675             :     }
     676             :   }
     677           0 :   return p;
     678             : }
     679             : 
     680             : GEN
     681          77 : perm_pow(GEN perm, GEN exp)
     682             : {
     683          77 :   long i, r = lg(perm)-1;
     684          77 :   GEN p = zero_zv(r);
     685          77 :   pari_sp av = avma;
     686          77 :   GEN v = cgetg(r+1, t_VECSMALL);
     687         273 :   for (i=1; i<=r; i++)
     688             :   {
     689             :     long e, n, k, l;
     690         196 :     if (p[i]) continue;
     691          77 :     v[1] = i;
     692         196 :     for (n=1, k=perm[i]; k!=i; k=perm[k], n++) v[n+1] = k;
     693          77 :     e = umodiu(exp, n);
     694         273 :     for (k = 1, l = e; k <= n; k++)
     695             :     {
     696         196 :       p[v[k]] = v[l+1];
     697         196 :       if (++l == n) l = 0;
     698             :     }
     699             :   }
     700          77 :   return gc_const(av, p);
     701             : }
     702             : 
     703             : GEN
     704       18907 : perm_powu(GEN perm, ulong exp)
     705             : {
     706       18907 :   ulong i, r = lg(perm)-1;
     707       18907 :   GEN p = zero_zv(r);
     708       18907 :   pari_sp av = avma;
     709       18907 :   GEN v = cgetg(r+1, t_VECSMALL);
     710      247667 :   for (i=1; i<=r; i++)
     711             :   {
     712             :     ulong e, n, k, l;
     713      228760 :     if (p[i]) continue;
     714       85036 :     v[1] = i;
     715      228760 :     for (n=1, k=perm[i]; k!=i; k=perm[k], n++) v[n+1] = k;
     716       85036 :     e = exp % n;
     717      313796 :     for (k = 1, l = e; k <= n; k++)
     718             :     {
     719      228760 :       p[v[k]] = v[l+1];
     720      228760 :       if (++l == n) l = 0;
     721             :     }
     722             :   }
     723       18907 :   return gc_const(av, p);
     724             : }
     725             : 
     726             : GEN
     727          21 : perm_to_GAP(GEN p)
     728             : {
     729          21 :   pari_sp ltop=avma;
     730             :   GEN gap;
     731             :   GEN x;
     732             :   long i;
     733          21 :   long nb, c=0;
     734             :   char *s;
     735             :   long sz;
     736          21 :   long lp=lg(p)-1;
     737          21 :   if (typ(p) != t_VECSMALL)  pari_err_TYPE("perm_to_GAP",p);
     738          21 :   x = perm_cycles(p);
     739          21 :   sz = (long) ((bfffo(lp)+1) * LOG10_2 + 1);
     740             :   /*Dry run*/
     741         133 :   for (i = 1, nb = 1; i < lg(x); ++i)
     742             :   {
     743         112 :     GEN z = gel(x,i);
     744         112 :     long lz = lg(z)-1;
     745         112 :     nb += 1+lz*(sz+2);
     746             :   }
     747          21 :   nb++;
     748             :   /*Real run*/
     749          21 :   gap = cgetg(nchar2nlong(nb) + 1, t_STR);
     750          21 :   s = GSTR(gap);
     751         133 :   for (i = 1; i < lg(x); ++i)
     752             :   {
     753             :     long j;
     754         112 :     GEN z = gel(x,i);
     755         112 :     if (lg(z) > 2)
     756             :     {
     757         112 :       s[c++] = '(';
     758         364 :       for (j = 1; j < lg(z); ++j)
     759             :       {
     760         252 :         if (j > 1)
     761             :         {
     762         140 :           s[c++] = ','; s[c++] = ' ';
     763             :         }
     764         252 :         sprintf(s+c,"%ld",z[j]);
     765         567 :         while(s[c++]) /* empty */;
     766         252 :         c--;
     767             :       }
     768         112 :       s[c++] = ')';
     769             :     }
     770             :   }
     771          21 :   if (!c) { s[c++]='('; s[c++]=')'; }
     772          21 :   s[c] = '\0';
     773          21 :   return gc_upto(ltop,gap);
     774             : }
     775             : 
     776             : int
     777      572537 : perm_commute(GEN s, GEN t)
     778             : {
     779      572537 :   long i, l = lg(t);
     780    40375545 :   for (i = 1; i < l; i++)
     781    39822398 :     if (t[ s[i] ] != s[ t[i] ]) return 0;
     782      553147 :   return 1;
     783             : }
     784             : 
     785             : /*************************************************************************/
     786             : /**                                                                     **/
     787             : /**                  Routines for handling groups                       **/
     788             : /**                                                                     **/
     789             : /*************************************************************************/
     790             : /* A Group is a t_VEC [gen,orders]
     791             :  * gen (vecvecsmall): list of generators given by permutations
     792             :  * orders (vecsmall): relatives orders of generators. */
     793      943733 : INLINE GEN grp_get_gen(GEN G) { return gel(G,1); }
     794     1599150 : INLINE GEN grp_get_ord(GEN G) { return gel(G,2); }
     795             : 
     796             : /* A Quotient Group is a t_VEC [gen,coset]
     797             :  * gen (vecvecsmall): coset generators
     798             :  * coset (vecsmall): gen[coset[p[1]]] generate the p-coset.
     799             :  */
     800      142100 : INLINE GEN quo_get_gen(GEN C) { return gel(C,1); }
     801       30114 : INLINE GEN quo_get_coset(GEN C) { return gel(C,2); }
     802             : 
     803             : static GEN
     804       52570 : trivialsubgroups(void)
     805       52570 : { GEN L = cgetg(2, t_VEC); gel(L,1) = trivialgroup(); return L; }
     806             : 
     807             : /* Compute the order of p modulo the group given by a set */
     808             : long
     809      220332 : perm_relorder(GEN p, GEN set)
     810             : {
     811      220332 :   pari_sp ltop = avma;
     812      220332 :   long n = 1, q = p[1];
     813      654759 :   while (!F2v_coeff(set,q)) { q = p[q]; n++; }
     814      220332 :   return gc_long(ltop,n);
     815             : }
     816             : 
     817             : GEN
     818       13104 : perm_generate(GEN S, GEN H, long o)
     819             : {
     820       13104 :   long i, n = lg(H)-1;
     821       13104 :   GEN L = cgetg(n*o + 1, t_VEC);
     822       45941 :   for(i=1; i<=n;     i++) gel(L,i) = vecsmall_copy(gel(H,i));
     823       50813 :   for(   ; i <= n*o; i++) gel(L,i) = perm_mul(gel(L,i-n), S);
     824       13104 :   return L;
     825             : }
     826             : 
     827             : /*Return the order (cardinality) of a group */
     828             : long
     829      711697 : group_order(GEN G)
     830             : {
     831      711697 :   return zv_prod(grp_get_ord(G));
     832             : }
     833             : 
     834             : /* G being a subgroup of S_n, output n */
     835             : long
     836       26740 : group_domain(GEN G)
     837             : {
     838       26740 :   GEN gen = grp_get_gen(G);
     839       26740 :   if (lg(gen) < 2) pari_err_DOMAIN("group_domain", "#G", "=", gen_1,G);
     840       26740 :   return lg(gel(gen,1)) - 1;
     841             : }
     842             : 
     843             : /*Left coset of g mod G: gG*/
     844             : GEN
     845      304654 : group_leftcoset(GEN G, GEN g)
     846             : {
     847      304654 :   GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     848      304654 :   GEN res = cgetg(group_order(G)+1, t_VEC);
     849             :   long i, j, k;
     850      304654 :   gel(res,1) = vecsmall_copy(g);
     851      304654 :   k = 1;
     852      560679 :   for (i = 1; i < lg(gen); i++)
     853             :   {
     854      256025 :     long c = k * (ord[i] - 1);
     855      705159 :     for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i));
     856             :   }
     857      304654 :   return res;
     858             : }
     859             : /*Right coset of g mod G: Gg*/
     860             : GEN
     861      182273 : group_rightcoset(GEN G, GEN g)
     862             : {
     863      182273 :   GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     864      182273 :   GEN res = cgetg(group_order(G)+1, t_VEC);
     865             :   long i, j, k;
     866      182273 :   gel(res,1) = vecsmall_copy(g);
     867      182273 :   k = 1;
     868      315581 :   for (i = 1; i < lg(gen); i++)
     869             :   {
     870      133308 :     long c = k * (ord[i] - 1);
     871      419517 :     for (j = 1; j <= c; j++) gel(res,++k) = perm_mul(gel(gen,i), gel(res,j));
     872             :   }
     873      182273 :   return res;
     874             : }
     875             : /*Elements of a group from the generators, cf group_leftcoset*/
     876             : GEN
     877      141162 : group_elts(GEN G, long n)
     878             : {
     879      141162 :   if (lg(G)==3 && typ(gel(G,1))==t_VEC)
     880             :   {
     881      141162 :     GEN gen = grp_get_gen(G), ord = grp_get_ord(G);
     882      141162 :     GEN res = cgetg(group_order(G)+1, t_VEC);
     883             :     long i, j, k;
     884      141162 :     gel(res,1) = identity_perm(n);
     885      141162 :     k = 1;
     886      286272 :     for (i = 1; i < lg(gen); i++)
     887             :     {
     888      145110 :       long c = k * (ord[i] - 1);
     889             :       /* j = 1, use res[1] = identity */
     890      145110 :       gel(res,++k) = vecsmall_copy(gel(gen,i));
     891      386589 :       for (j = 2; j <= c; j++) gel(res,++k) = perm_mul(gel(res,j), gel(gen,i));
     892             :     }
     893      141162 :     return res;
     894           0 :   } else return gcopy(G);
     895             : }
     896             : 
     897             : GEN
     898       14448 : groupelts_conj_set(GEN elts, GEN p)
     899             : {
     900       14448 :   long i, j, l = lg(elts), n = lg(p)-1;
     901       14448 :   GEN res = zero_F2v(n);
     902      241465 :   for(j = 1; j < n; j++)
     903      241465 :     if (p[j]==1) break;
     904      101136 :   for(i = 1; i < l; i++)
     905       86688 :     F2v_set(res, p[mael(elts,i,j)]);
     906       14448 :   return res;
     907             : }
     908             : 
     909             : GEN
     910       28182 : groupelts_set(GEN elts, long n)
     911             : {
     912       28182 :   GEN res = zero_F2v(n);
     913       28182 :   long i, l = lg(elts);
     914      137886 :   for(i=1; i<l; i++)
     915      109704 :     F2v_set(res,mael(elts,i,1));
     916       28182 :   return res;
     917             : }
     918             : 
     919             : /*Elements of a group from the generators, returned as a set (bitmap)*/
     920             : GEN
     921       90727 : group_set(GEN G, long n)
     922             : {
     923       90727 :   GEN res = zero_F2v(n);
     924       90727 :   pari_sp av = avma;
     925       90727 :   GEN elts = group_elts(G, n);
     926       90727 :   long i, l = lg(elts);
     927      284326 :   for(i=1; i<l; i++)
     928      193599 :     F2v_set(res,mael(elts,i,1));
     929       90727 :   return gc_const(av, res);
     930             : }
     931             : 
     932             : static int
     933       17353 : sgcmp(GEN a, GEN b) { return vecsmall_lexcmp(gel(a,1),gel(b,1)); }
     934             : 
     935             : GEN
     936         497 : subgroups_tableset(GEN S, long n)
     937             : {
     938         497 :   long i, l = lg(S);
     939         497 :   GEN  v = cgetg(l, t_VEC);
     940        5411 :   for(i=1; i<l; i++)
     941        4914 :     gel(v,i) = mkvec2(group_set(gel(S,i), n), mkvecsmall(i));
     942         497 :   gen_sort_inplace(v,(void*)sgcmp,cmp_nodata, NULL);
     943         497 :   return v;
     944             : }
     945             : 
     946             : long
     947        2002 : tableset_find_index(GEN tbl, GEN set)
     948             : {
     949        2002 :   long i = tablesearch(tbl,mkvec2(set,mkvecsmall(0)),sgcmp);
     950        2002 :   if (!i) return 0;
     951        2002 :   return mael3(tbl,i,2,1);
     952             : }
     953             : 
     954             : GEN
     955       52598 : trivialgroup(void) { retmkvec2(cgetg(1,t_VEC), cgetg(1,t_VECSMALL)); }
     956             : 
     957             : /*Cyclic group generated by g of order s*/
     958             : GEN
     959       27972 : cyclicgroup(GEN g, long s)
     960       27972 : { retmkvec2(mkvec( vecsmall_copy(g) ), mkvecsmall(s)); }
     961             : 
     962             : /*Return the group generated by g1,g2 of relative orders s1,s2*/
     963             : GEN
     964        1085 : dicyclicgroup(GEN g1, GEN g2, long s1, long s2)
     965        1085 : { retmkvec2( mkvec2(vecsmall_copy(g1), vecsmall_copy(g2)),
     966             :              mkvecsmall2(s1, s2) ); }
     967             : 
     968             : /* return the quotient map G --> G/H */
     969             : /*The ouput is [gen,hash]*/
     970             : /* gen (vecvecsmall): coset generators
     971             :  * coset (vecsmall): vecsmall of coset number) */
     972             : GEN
     973       11781 : groupelts_quotient(GEN elt, GEN H)
     974             : {
     975       11781 :   pari_sp ltop = avma;
     976             :   GEN  p2, p3;
     977       11781 :   long i, j, a = 1;
     978       11781 :   long n = lg(gel(elt,1))-1, o = group_order(H);
     979             :   GEN  el;
     980       11781 :   long le = lg(elt)-1;
     981       11781 :   GEN used = zero_F2v(le+1);
     982       11781 :   long l = le/o;
     983       11781 :   p2 = cgetg(l+1, t_VEC);
     984       11781 :   p3 = zero_zv(n);
     985       11781 :   el = zero_zv(n);
     986      150549 :   for (i = 1; i<=le; i++)
     987      138768 :     el[mael(elt,i,1)]=i;
     988       68880 :   for (i = 1; i <= l; ++i)
     989             :   {
     990             :     GEN V;
     991      150899 :     while(F2v_coeff(used,a)) a++;
     992       57106 :     V = group_leftcoset(H,gel(elt,a));
     993       57106 :     gel(p2,i) = gel(V,1);
     994      195769 :     for(j=1;j<lg(V);j++)
     995             :     {
     996      138670 :       long b = el[mael(V,j,1)];
     997      138670 :       if (b==0) pari_err_IMPL("group_quotient for a non-WSS group");
     998      138663 :       F2v_set(used,b);
     999             :     }
    1000      195755 :     for (j = 1; j <= o; j++)
    1001      138656 :       p3[mael(V, j, 1)] = i;
    1002             :   }
    1003       11774 :   return gc_GEN(ltop,mkvec2(p2,p3));
    1004             : }
    1005             : 
    1006             : GEN
    1007       10269 : group_quotient(GEN G, GEN H)
    1008             : {
    1009       10269 :   return groupelts_quotient(group_elts(G, group_domain(G)), H);
    1010             : }
    1011             : 
    1012             : /*Compute the image of a permutation by a quotient map.*/
    1013             : GEN
    1014       30114 : quotient_perm(GEN C, GEN p)
    1015             : {
    1016       30114 :   GEN gen = quo_get_gen(C);
    1017       30114 :   GEN coset = quo_get_coset(C);
    1018       30114 :   long j, l = lg(gen);
    1019       30114 :   GEN p3 = cgetg(l, t_VECSMALL);
    1020      283409 :   for (j = 1; j < l; ++j)
    1021             :   {
    1022      253295 :     p3[j] = coset[p[mael(gen,j,1)]];
    1023      253295 :     if (p3[j]==0) pari_err_IMPL("quotient_perm for a non-WSS group");
    1024             :   }
    1025       30114 :   return p3;
    1026             : }
    1027             : 
    1028             : /* H is a subgroup of G, C is the quotient map G --> G/H
    1029             :  *
    1030             :  * Lift a subgroup S of G/H to a subgroup of G containing H */
    1031             : GEN
    1032       50862 : quotient_subgroup_lift(GEN C, GEN H, GEN S)
    1033             : {
    1034       50862 :   GEN genH = grp_get_gen(H);
    1035       50862 :   GEN genS = grp_get_gen(S);
    1036       50862 :   GEN genC = quo_get_gen(C);
    1037       50862 :   long l1 = lg(genH)-1;
    1038       50862 :   long l2 = lg(genS)-1, j;
    1039       50862 :   GEN p1 = cgetg(3, t_VEC), L = cgetg(l1+l2+1, t_VEC);
    1040      101892 :   for (j = 1; j <= l1; ++j) gel(L,j) = gel(genH,j);
    1041      118237 :   for (j = 1; j <= l2; ++j) gel(L,l1+j) = gel(genC, mael(genS,j,1));
    1042       50862 :   gel(p1,1) = L;
    1043       50862 :   gel(p1,2) = vecsmall_concat(grp_get_ord(H), grp_get_ord(S));
    1044       50862 :   return p1;
    1045             : }
    1046             : 
    1047             : /* Let G a group and C a quotient map G --> G/H
    1048             :  * Assume H is normal, return the group G/H */
    1049             : GEN
    1050       10262 : quotient_group(GEN C, GEN G)
    1051             : {
    1052       10262 :   pari_sp ltop = avma;
    1053             :   GEN Qgen, Qord, Qelt, Qset, Q;
    1054       10262 :   GEN Cgen = quo_get_gen(C);
    1055       10262 :   GEN Ggen = grp_get_gen(G);
    1056       10262 :   long i,j, n = lg(Cgen)-1, l = lg(Ggen);
    1057       10262 :   Qord = cgetg(l, t_VECSMALL);
    1058       10262 :   Qgen = cgetg(l, t_VEC);
    1059       10262 :   Qelt = mkvec(identity_perm(n));
    1060       10262 :   Qset = groupelts_set(Qelt, n);
    1061       31276 :   for (i = 1, j = 1; i < l; ++i)
    1062             :   {
    1063       21014 :     GEN  g = quotient_perm(C, gel(Ggen,i));
    1064       21014 :     long o = perm_relorder(g, Qset);
    1065       21014 :     gel(Qgen,j) = g;
    1066       21014 :     Qord[j] = o;
    1067       21014 :     if (o != 1)
    1068             :     {
    1069       13104 :       Qelt = perm_generate(g, Qelt, o);
    1070       13104 :       Qset = groupelts_set(Qelt, n);
    1071       13104 :       j++;
    1072             :     }
    1073             :   }
    1074       10262 :   setlg(Qgen,j);
    1075       10262 :   setlg(Qord,j); Q = mkvec2(Qgen, Qord);
    1076       10262 :   return gc_GEN(ltop,Q);
    1077             : }
    1078             : 
    1079             : GEN
    1080        1512 : quotient_groupelts(GEN C)
    1081             : {
    1082        1512 :   GEN G = quo_get_gen(C);
    1083        1512 :   long i, l = lg(G);
    1084        1512 :   GEN Q = cgetg(l, t_VEC);
    1085       10612 :   for (i = 1; i < l; ++i)
    1086        9100 :     gel(Q,i) = quotient_perm(C, gel(G,i));
    1087        1512 :   return Q;
    1088             : }
    1089             : 
    1090             : /* Return 1 if g normalizes N, 0 otherwise */
    1091             : long
    1092      182273 : group_perm_normalize(GEN N, GEN g)
    1093             : {
    1094      182273 :   pari_sp ltop = avma;
    1095      182273 :   long r = gequal(vecvecsmall_sort_shallow(group_leftcoset(N, g)),
    1096             :                   vecvecsmall_sort_shallow(group_rightcoset(N, g)));
    1097      182273 :   return gc_long(ltop, r);
    1098             : }
    1099             : 
    1100             : /* L is a list of subgroups, C is a coset and r a relative order.*/
    1101             : static GEN
    1102       65275 : liftlistsubgroups(GEN L, GEN C, long r)
    1103             : {
    1104       65275 :   pari_sp ltop = avma;
    1105       65275 :   long c = lg(C)-1, l = lg(L)-1, n = lg(gel(C,1))-1, i, k;
    1106             :   GEN R;
    1107       65275 :   if (!l) return cgetg(1,t_VEC);
    1108       58583 :   R = cgetg(l*c+1, t_VEC);
    1109      143080 :   for (i = 1, k = 1; i <= l; ++i)
    1110             :   {
    1111       84497 :     GEN S = gel(L,i), Selt = group_set(S,n);
    1112       84497 :     GEN gen = grp_get_gen(S);
    1113       84497 :     GEN ord = grp_get_ord(S);
    1114             :     long j;
    1115      279370 :     for (j = 1; j <= c; ++j)
    1116             :     {
    1117      194873 :       GEN p = gel(C,j);
    1118      194873 :       if (perm_relorder(p, Selt) == r && group_perm_normalize(S, p))
    1119      108759 :         gel(R,k++) = mkvec2(vec_append(gen, p),
    1120             :                             vecsmall_append(ord, r));
    1121             :     }
    1122             :   }
    1123       58583 :   setlg(R, k);
    1124       58583 :   return gc_GEN(ltop, R);
    1125             : }
    1126             : 
    1127             : /* H is a normal subgroup, C is the quotient map G -->G/H,
    1128             :  * S is a subgroup of G/H, and G is embedded in Sym(l)
    1129             :  * Return all the subgroups K of G such that
    1130             :  * S= K mod H and K inter H={1} */
    1131             : static GEN
    1132       49350 : liftsubgroup(GEN C, GEN H, GEN S)
    1133             : {
    1134       49350 :   pari_sp ltop = avma;
    1135       49350 :   GEN V = trivialsubgroups();
    1136       49350 :   GEN Sgen = grp_get_gen(S);
    1137       49350 :   GEN Sord = grp_get_ord(S);
    1138       49350 :   GEN Cgen = quo_get_gen(C);
    1139       49350 :   long n = lg(Sgen), i;
    1140      114625 :   for (i = 1; i < n; ++i)
    1141             :   { /*loop over generators of S*/
    1142       65275 :     GEN W = group_leftcoset(H, gel(Cgen, mael(Sgen, i, 1)));
    1143       65275 :     V = liftlistsubgroups(V, W, Sord[i]);
    1144             :   }
    1145       49350 :   return gc_GEN(ltop,V);
    1146             : }
    1147             : 
    1148             : /* 1:A4, 2:S4, 3:F36, 0: other */
    1149             : long
    1150       10094 : group_isA4S4(GEN G)
    1151             : {
    1152       10094 :   GEN elt = grp_get_gen(G);
    1153       10094 :   GEN ord = grp_get_ord(G);
    1154       10094 :   long n = lg(ord);
    1155       10094 :   if (n != 4 && n != 5) return 0;
    1156        2219 :   if (n==4 && ord[1]==3 && ord[2]==3 && ord[3]==4)
    1157             :   {
    1158             :     long i;
    1159           7 :     GEN p = gel(elt,1), q = gel(elt,2), r = gel(elt,3);
    1160         259 :     for(i=1; i<=36; i++)
    1161         252 :       if (p[r[i]]!=r[q[i]]) return 0;
    1162           7 :     return 3;
    1163             :   }
    1164        2212 :   if (ord[1]!=2 || ord[2]!=2 || ord[3]!=3) return 0;
    1165          42 :   if (perm_commute(gel(elt,1),gel(elt,3))) return 0;
    1166          42 :   if (n==4) return 1;
    1167          21 :   if (ord[4]!=2) return 0;
    1168          21 :   if (perm_commute(gel(elt,3),gel(elt,4))) return 0;
    1169          21 :   return 2;
    1170             : }
    1171             : /* compute all the subgroups of a group G */
    1172             : GEN
    1173       13314 : group_subgroups(GEN G)
    1174             : {
    1175       13314 :   pari_sp ltop = avma;
    1176             :   GEN p1, H, C, Q, M, sg1, sg2, sg3;
    1177       13314 :   GEN gen = grp_get_gen(G);
    1178       13314 :   GEN ord = grp_get_ord(G);
    1179       13314 :   long lM, i, j, n = lg(gen);
    1180             :   long t;
    1181       13314 :   if (n == 1) return trivialsubgroups();
    1182       10094 :   t = group_isA4S4(G);
    1183       10094 :   if (t == 3)
    1184             :   {
    1185           7 :     GEN H = mkvec2(mkvec3(gel(gen,1), gel(gen,2), perm_sqr(gel(gen,3))),
    1186             :                    mkvecsmall3(3, 3, 2));
    1187           7 :     GEN S = group_subgroups(H);
    1188           7 :     GEN V = cgetg(11,t_VEC);
    1189           7 :     gel(V,1) = cyclicgroup(gel(gen,3),4);
    1190          63 :     for (i=2; i<10; i++)
    1191          56 :       gel(V,i) = cyclicgroup(perm_mul(gmael3(V,i-1,1,1),gel(gen,i%3==1 ? 2:1)),4);
    1192           7 :     gel(V,10) = G;
    1193           7 :     return gc_GEN(ltop,shallowconcat(S,V));
    1194             :   }
    1195       10087 :   else if (t)
    1196             :   {
    1197          42 :     GEN s = gel(gen,1);       /*s = (1,2)(3,4) */
    1198          42 :     GEN t = gel(gen,2);       /*t = (1,3)(2,4) */
    1199          42 :     GEN st = perm_mul(s, t); /*st = (1,4)(2,3) */
    1200          42 :     H = dicyclicgroup(s, t, 2, 2);
    1201             :     /* sg3 is the list of subgroups intersecting only partially with H*/
    1202          42 :     sg3 = cgetg((n==4)?4: 10, t_VEC);
    1203          42 :     gel(sg3,1) = cyclicgroup(s, 2);
    1204          42 :     gel(sg3,2) = cyclicgroup(t, 2);
    1205          42 :     gel(sg3,3) = cyclicgroup(st, 2);
    1206          42 :     if (n==5)
    1207             :     {
    1208          21 :       GEN u = gel(gen,3);
    1209          21 :       GEN v = gel(gen,4), w, u2;
    1210          21 :       if (zv_equal(perm_conj(u,s), t)) /*u=(2,3,4)*/
    1211          21 :         u2 = perm_sqr(u);
    1212             :       else
    1213             :       {
    1214           0 :         u2 = u;
    1215           0 :         u = perm_sqr(u);
    1216             :       }
    1217          21 :       if (perm_orderu(v)==2)
    1218             :       {
    1219          21 :         if (!perm_commute(s,v)) /*v=(1,2)*/
    1220             :         {
    1221           0 :           v = perm_conj(u,v);
    1222           0 :           if (!perm_commute(s,v)) v = perm_conj(u,v);
    1223             :         }
    1224          21 :         w = perm_mul(v,t); /*w=(1,4,2,3)*/
    1225             :       }
    1226             :       else
    1227             :       {
    1228           0 :         w = v;
    1229           0 :         if (!zv_equal(perm_sqr(w), s)) /*w=(1,4,2,3)*/
    1230             :         {
    1231           0 :           w = perm_conj(u,w);
    1232           0 :           if (!zv_equal(perm_sqr(w), s)) w = perm_conj(u,w);
    1233             :         }
    1234           0 :         v = perm_mul(w,t); /*v=(1,2)*/
    1235             :       }
    1236          21 :       gel(sg3,4) = dicyclicgroup(s,v,2,2);
    1237          21 :       gel(sg3,5) = dicyclicgroup(t,perm_conj(u,v),2,2);
    1238          21 :       gel(sg3,6) = dicyclicgroup(st,perm_conj(u2,v),2,2);
    1239          21 :       gel(sg3,7) = dicyclicgroup(s,w,2,2);
    1240          21 :       gel(sg3,8) = dicyclicgroup(t,perm_conj(u,w),2,2);
    1241          21 :       gel(sg3,9) = dicyclicgroup(st,perm_conj(u2,w),2,2);
    1242             :     }
    1243             :   }
    1244             :   else
    1245             :   {
    1246       10045 :     ulong osig = mael(factoru(ord[1]), 1, 1);
    1247       10045 :     GEN sig = perm_powu(gel(gen,1), ord[1]/osig);
    1248       10045 :     H = cyclicgroup(sig,osig);
    1249       10045 :     sg3 = NULL;
    1250             :   }
    1251       10087 :   C = group_quotient(G,H);
    1252       10080 :   Q = quotient_group(C,G);
    1253       10080 :   M = group_subgroups(Q); lM = lg(M);
    1254             :   /* sg1 is the list of subgroups containing H*/
    1255       10073 :   sg1 = cgetg(lM, t_VEC);
    1256       59423 :   for (i = 1; i < lM; ++i) gel(sg1,i) = quotient_subgroup_lift(C,H,gel(M,i));
    1257             :   /*sg2 is a list of lists of subgroups not intersecting with H*/
    1258       10073 :   sg2 = cgetg(lM, t_VEC);
    1259             :   /* Loop over all subgroups of G/H */
    1260       59423 :   for (j = 1; j < lM; ++j) gel(sg2,j) = liftsubgroup(C, H, gel(M,j));
    1261       10073 :   p1 = gconcat(sg1, shallowconcat1(sg2));
    1262       10073 :   if (sg3)
    1263             :   {
    1264          42 :     p1 = gconcat(p1, sg3);
    1265          42 :     if (n==5) /*ensure that the D4 subgroups of S4 are in supersolvable format*/
    1266          84 :       for(j = 3; j <= 5; j++)
    1267             :       {
    1268          63 :         GEN c = gmael(p1,j,1);
    1269          63 :         if (!perm_commute(gel(c,1),gel(c,3)))
    1270             :         {
    1271          42 :           if (perm_commute(gel(c,2),gel(c,3))) { swap(gel(c,1), gel(c,2)); }
    1272             :           else
    1273          21 :             perm_mul_inplace2(gel(c,2), gel(c,1));
    1274             :         }
    1275             :       }
    1276             :   }
    1277       10073 :   return gc_upto(ltop,p1);
    1278             : }
    1279             : 
    1280             : /*return 1 if G is abelian, else 0*/
    1281             : long
    1282        8946 : group_isabelian(GEN G)
    1283             : {
    1284        8946 :   GEN g = grp_get_gen(G);
    1285        8946 :   long i, j, n = lg(g);
    1286       12894 :   for(i=2; i<n; i++)
    1287       13104 :     for(j=1; j<i; j++)
    1288        9156 :       if (!perm_commute(gel(g,i), gel(g,j))) return 0;
    1289        4004 :   return 1;
    1290             : }
    1291             : 
    1292             : /*If G is abelian, return its HNF matrix*/
    1293             : GEN
    1294         385 : group_abelianHNF(GEN G, GEN S)
    1295             : {
    1296         385 :   GEN M, g = grp_get_gen(G), o = grp_get_ord(G);
    1297         385 :   long i, j, k, n = lg(g);
    1298         385 :   if (!group_isabelian(G)) return NULL;
    1299         315 :   if (n==1) return cgetg(1,t_MAT);
    1300         301 :   if (!S) S = group_elts(G, group_domain(G));
    1301         301 :   M = cgetg(n,t_MAT);
    1302         980 :   for(i=1; i<n; i++)
    1303             :   {
    1304         679 :     GEN P, C = cgetg(n,t_COL);
    1305         679 :     pari_sp av = avma;
    1306         679 :     gel(M,i) = C;
    1307         679 :     P = perm_inv(perm_powu(gel(g,i), o[i]));
    1308         959 :     for(j=1; j<lg(S); j++)
    1309         959 :       if (zv_equal(P, gel(S,j))) break;
    1310         679 :     set_avma(av);
    1311         679 :     if (j==lg(S)) pari_err_BUG("galoisisabelian [inconsistent group]");
    1312         679 :     j--;
    1313        1218 :     for(k=1; k<i; k++)
    1314             :     {
    1315         539 :       long q = j / o[k];
    1316         539 :       gel(C,k) = stoi(j - q*o[k]);
    1317         539 :       j = q;
    1318             :     }
    1319         679 :     gel(C,k) = stoi(o[i]);
    1320        1218 :     for (k++; k<n; k++) gel(C,k) = gen_0;
    1321             :   }
    1322         301 :   return M;
    1323             : }
    1324             : 
    1325             : /*If G is abelian, return its abstract SNF matrix*/
    1326             : GEN
    1327         336 : group_abelianSNF(GEN G, GEN L)
    1328             : {
    1329         336 :   pari_sp ltop = avma;
    1330         336 :   GEN H = group_abelianHNF(G,L);
    1331         336 :   if (!H) return NULL;
    1332         266 :   return gc_upto(ltop, smithclean( ZM_snf(H) ));
    1333             : }
    1334             : 
    1335             : GEN
    1336         462 : abelian_group(GEN v)
    1337             : {
    1338         462 :   long card = zv_prod(v), i, d = 1, l = lg(v);
    1339         462 :   GEN G = cgetg(3,t_VEC), gen = cgetg(l,t_VEC);
    1340         462 :   gel(G,1) = gen;
    1341         462 :   gel(G,2) = vecsmall_copy(v);
    1342         959 :   for(i=1; i<l; i++)
    1343             :   {
    1344         497 :     GEN p = cgetg(card+1, t_VECSMALL);
    1345         497 :     long o = v[i], u = d*(o-1), j, k, l;
    1346         497 :     gel(gen, i) = p;
    1347             :     /* The following loop is over-optimized. Remember that I wrote it for
    1348             :      * testpermutation. Something has survived... BA */
    1349        1246 :     for(j=1;j<=card;)
    1350             :     {
    1351        3122 :       for(k=1;k<o;k++)
    1352        6615 :         for(l=1;l<=d; l++,j++) p[j] = j+d;
    1353        2779 :       for (l=1; l<=d; l++,j++) p[j] = j-u;
    1354             :     }
    1355         497 :     d += u;
    1356             :   }
    1357         462 :   return G;
    1358             : }
    1359             : 
    1360             : static long
    1361       14609 : groupelts_subgroup_isnormal(GEN G, GEN H)
    1362             : {
    1363       14609 :   long i, n = lg(G);
    1364       64470 :   for(i = 1; i < n; i++)
    1365       62895 :     if (!group_perm_normalize(H, gel(G,i))) return 0;
    1366        1575 :   return 1;
    1367             : }
    1368             : 
    1369             : /*return 1 if H is a normal subgroup of G*/
    1370             : long
    1371         336 : group_subgroup_isnormal(GEN G, GEN H)
    1372             : {
    1373         336 :   if (lg(grp_get_gen(H)) > 1 && group_domain(G) != group_domain(H))
    1374           0 :     pari_err_DOMAIN("group_subgroup_isnormal","domain(H)","!=",
    1375             :                     strtoGENstr("domain(G)"), H);
    1376         336 :   return groupelts_subgroup_isnormal(grp_get_gen(G), H);
    1377             : }
    1378             : 
    1379             : static GEN
    1380        4816 : group_subgroup_kernel_set(GEN G, GEN H)
    1381             : {
    1382             :   pari_sp av;
    1383        4816 :   GEN g = grp_get_gen(G);
    1384        4816 :   long i, n = lg(g);
    1385             :   GEN S, elts;
    1386        4816 :   long d = group_domain(G);
    1387        4816 :   if (lg(grp_get_gen(H)) > 1 && group_domain(G) != group_domain(H))
    1388           0 :     pari_err_DOMAIN("group_subgroup_isnormal","domain(H)","!=",
    1389             :                     strtoGENstr("domain(G)"), H);
    1390        4816 :   elts = group_elts(H,d);
    1391        4816 :   S = groupelts_set(elts, d);
    1392        4816 :   av = avma;
    1393       19264 :   for(i=1; i<n; i++)
    1394             :   {
    1395       14448 :     F2v_and_inplace(S, groupelts_conj_set(elts,gel(g,i)));
    1396       14448 :     set_avma(av);
    1397             :   }
    1398        4816 :   return S;
    1399             : }
    1400             : 
    1401             : int
    1402        4816 : group_subgroup_is_faithful(GEN G, GEN H)
    1403             : {
    1404        4816 :   pari_sp av = avma;
    1405        4816 :   GEN K = group_subgroup_kernel_set(G,H);
    1406        4816 :   F2v_clear(K,1);
    1407        4816 :   return gc_long(av, F2v_equal0(K));
    1408             : }
    1409             : 
    1410             : long
    1411           0 : groupelts_exponent(GEN elts)
    1412             : {
    1413           0 :   long i, n = lg(elts)-1, expo = 1;
    1414           0 :   for(i=1; i<=n; i++) expo = ulcm(expo, perm_orderu(gel(elts,i)));
    1415           0 :   return expo;
    1416             : }
    1417             : 
    1418             : GEN
    1419         700 : groupelts_center(GEN S)
    1420             : {
    1421         700 :   pari_sp ltop = avma;
    1422         700 :   long i, j, n = lg(S)-1, l = n;
    1423         700 :   GEN V, elts = zero_F2v(n+1);
    1424       25732 :   for(i=1; i<=n; i++)
    1425             :   {
    1426       25032 :     if (F2v_coeff(elts,i)) { l--;  continue; }
    1427      573384 :     for(j=1; j<=n; j++)
    1428      563192 :       if (!perm_commute(gel(S,i),gel(S,j)))
    1429             :       {
    1430       14322 :         F2v_set(elts,i);
    1431       14322 :         F2v_set(elts,j); l--; break;
    1432             :       }
    1433             :   }
    1434         700 :   V = cgetg(l+1,t_VEC);
    1435       25732 :   for (i=1, j=1; i<=n ;i++)
    1436       25032 :     if (!F2v_coeff(elts,i)) gel(V,j++) = vecsmall_copy(gel(S,i));
    1437         700 :   return gc_upto(ltop,V);
    1438             : }
    1439             : 
    1440             : GEN
    1441        4270 : groupelts_conjclasses(GEN elts, long *pnbcl)
    1442             : {
    1443        4270 :   long i, j, cl = 0, n = lg(elts)-1;
    1444        4270 :   GEN c = const_vecsmall(n,0);
    1445        4270 :   pari_sp av = avma;
    1446       52850 :   for (i=1; i<=n; i++)
    1447             :   {
    1448       48580 :     GEN g = gel(elts,i);
    1449       48580 :     if (c[i]) continue;
    1450       34965 :     c[i] = ++cl;
    1451      486871 :     for(j=1; j<=n; j++)
    1452      451906 :       if (j != i)
    1453             :       {
    1454      416941 :         GEN h = perm_conj(gel(elts,j), g);
    1455      416941 :         long i2 = gen_search(elts,h,(void*)&vecsmall_lexcmp,&cmp_nodata);
    1456      416941 :         c[i2] = cl; set_avma(av);
    1457             :       }
    1458             :   }
    1459        4270 :   if (pnbcl) *pnbcl = cl;
    1460        4270 :   return c;
    1461             : }
    1462             : 
    1463             : GEN
    1464        4270 : conjclasses_repr(GEN conj, long nb)
    1465             : {
    1466        4270 :   long i, l = lg(conj);
    1467        4270 :   GEN e = const_vecsmall(nb, 0);
    1468       52850 :   for(i=1; i<l; i++)
    1469             :   {
    1470       48580 :     long ci = conj[i];
    1471       48580 :     if (!e[ci]) e[ci] = i;
    1472             :   }
    1473        4270 :   return e;
    1474             : }
    1475             : 
    1476             : /* elts of G sorted wrt vecsmall_lexcmp order: g in G is determined by g[1]
    1477             :  * so sort by increasing g[1] */
    1478             : static GEN
    1479        3885 : galois_elts_sorted(GEN gal)
    1480             : {
    1481             :   long i, l;
    1482        3885 :   GEN elts = gal_get_group(gal), v = cgetg_copy(elts, &l);
    1483       43141 :   for (i = 1; i < l; i++) { GEN g = gel(elts,i); gel(v, g[1]) = g; }
    1484        3885 :   return v;
    1485             : }
    1486             : GEN
    1487        4291 : group_to_cc(GEN G)
    1488             : {
    1489        4291 :   GEN elts = checkgroupelts(G), z = cgetg(5,t_VEC);
    1490        4270 :   long n, flag = 1;
    1491        4270 :   if (typ(gel(G,1)) == t_POL)
    1492        3885 :     elts = galois_elts_sorted(G); /* galoisinit */
    1493             :   else
    1494             :   {
    1495         385 :     long i, l = lg(elts);
    1496         385 :     elts = gen_sort_shallow(elts,(void*)vecsmall_lexcmp,cmp_nodata);
    1497        5824 :     for (i = 1; i < l; i++)
    1498        5586 :       if (gel(elts,i)[1] != i) { flag = 0; break; }
    1499             :   }
    1500        4270 :   gel(z,1) = elts;
    1501        4270 :   gel(z,2) = groupelts_conjclasses(elts,&n);
    1502        4270 :   gel(z,3) = conjclasses_repr(gel(z,2),n);
    1503        4270 :   gel(z,4) = utoi(flag); return z;
    1504             : }
    1505             : 
    1506             : /* S a list of generators */
    1507             : GEN
    1508           0 : groupelts_abelian_group(GEN S)
    1509             : {
    1510           0 :   pari_sp ltop = avma;
    1511             :   GEN Qgen, Qord, Qelt;
    1512           0 :   long i, j, n = lg(gel(S,1))-1, l = lg(S);
    1513           0 :   Qord = cgetg(l, t_VECSMALL);
    1514           0 :   Qgen = cgetg(l, t_VEC);
    1515           0 :   Qelt = mkvec(identity_perm(n));
    1516           0 :   for (i = 1, j = 1; i < l; ++i)
    1517             :   {
    1518           0 :     GEN  g = gel(S,i);
    1519           0 :     long o = perm_relorder(g, groupelts_set(Qelt, n));
    1520           0 :     gel(Qgen,j) = g;
    1521           0 :     Qord[j] = o;
    1522           0 :     if (o != 1) { Qelt = perm_generate(g, Qelt, o); j++; }
    1523             :   }
    1524           0 :   setlg(Qgen,j);
    1525           0 :   setlg(Qord,j);
    1526           0 :   return gc_GEN(ltop, mkvec2(Qgen, Qord));
    1527             : }
    1528             : 
    1529             : GEN
    1530          14 : group_export_GAP(GEN G)
    1531             : {
    1532          14 :   pari_sp av = avma;
    1533          14 :   GEN s, comma, g = grp_get_gen(G);
    1534          14 :   long i, k, l = lg(g);
    1535          14 :   if (l == 1) return strtoGENstr("Group(())");
    1536           7 :   s = cgetg(2*l, t_VEC);
    1537           7 :   comma = strtoGENstr(", ");
    1538           7 :   gel(s,1) = strtoGENstr("Group(");
    1539          28 :   for (i=1, k=2; i < l; ++i)
    1540             :   {
    1541          21 :     if (i > 1) gel(s,k++) = comma;
    1542          21 :     gel(s,k++) = perm_to_GAP(gel(g,i));
    1543             :   }
    1544           7 :   gel(s,k++) = strtoGENstr(")");
    1545           7 :   return gc_GEN(av, shallowconcat1(s));
    1546             : }
    1547             : 
    1548             : GEN
    1549          14 : group_export_MAGMA(GEN G)
    1550             : {
    1551          14 :   pari_sp av = avma;
    1552          14 :   GEN s, comma, g = grp_get_gen(G);
    1553          14 :   long i, k, l = lg(g);
    1554          14 :   if (l == 1) return strtoGENstr("PermutationGroup<1|>");
    1555           7 :   s = cgetg(2*l, t_VEC);
    1556           7 :   comma = strtoGENstr(", ");
    1557           7 :   gel(s,1) = gsprintf("PermutationGroup<%ld|",group_domain(G));
    1558          28 :   for (i=1, k=2; i < l; ++i)
    1559             :   {
    1560          21 :     if (i > 1) gel(s,k++) = comma;
    1561          21 :     gel(s,k++) = GENtoGENstr( vecsmall_to_vec(gel(g,i)) );
    1562             :   }
    1563           7 :   gel(s,k++) = strtoGENstr(">");
    1564           7 :   return gc_GEN(av, shallowconcat1(s));
    1565             : }
    1566             : 
    1567             : GEN
    1568          28 : group_export(GEN G, long format)
    1569             : {
    1570          28 :   switch(format)
    1571             :   {
    1572          14 :   case 0: return group_export_GAP(G);
    1573          14 :   case 1: return group_export_MAGMA(G);
    1574             :   }
    1575           0 :   pari_err_FLAG("galoisexport");
    1576           0 :   return NULL; /*-Wall*/
    1577             : }
    1578             : 
    1579             : static GEN
    1580        3577 : groupelts_cyclic_subgroups(GEN G)
    1581             : {
    1582        3577 :   pari_sp av = avma;
    1583        3577 :   long i, j, n = lg(G)-1;
    1584             :   GEN elts, f, gen, ord;
    1585        3577 :   if (n==1) return cgetg(1,t_VEC);
    1586        3577 :   elts = zero_F2v(lg(gel(G,1))-1);
    1587        3577 :   gen = cgetg(n+1, t_VECSMALL);
    1588        3577 :   ord = cgetg(n+1, t_VECSMALL);
    1589       53109 :   for (i=1, j=1; i<=n; i++)
    1590             :   {
    1591       49532 :     long k = 1, o, c = 0;
    1592       49532 :     GEN p = gel(G, i);
    1593       49532 :     if (F2v_coeff(elts, p[1])) continue;
    1594       35903 :     o = perm_orderu(p);
    1595       35903 :     gen[j] = i; ord[j] = o; j++;
    1596             :     do
    1597             :     {
    1598       96229 :       if (cgcd(o, ++c)==1) F2v_set(elts, p[k]);
    1599       96229 :       k = p[k];
    1600       96229 :     } while (k!=1);
    1601             :   }
    1602        3577 :   setlg(gen, j);
    1603        3577 :   setlg(ord, j);
    1604        3577 :   f = vecsmall_indexsort(ord);
    1605        3577 :   return gc_GEN(av, mkvec2(vecsmallpermute(gen, f),
    1606             :                                  vecsmallpermute(ord, f)));
    1607             : }
    1608             : 
    1609             : GEN
    1610        3584 : groupelts_to_group(GEN G)
    1611             : {
    1612        3584 :   pari_sp av = avma;
    1613             :   GEN L, cyc, ord;
    1614        3584 :   long i, l, n = lg(G)-1;
    1615        3584 :   if (n==1) return trivialgroup();
    1616        3563 :   L = groupelts_cyclic_subgroups(G);
    1617        3563 :   cyc = gel(L,1); ord = gel(L,2);
    1618        3563 :   l = lg(cyc);
    1619       16324 :   for (i = l-1; i >= 2; i--)
    1620             :   {
    1621       15645 :     GEN p = gel(G,cyc[i]);
    1622       15645 :     long o = ord[i];
    1623       15645 :     GEN H = cyclicgroup(p, o);
    1624       15645 :     if (o == n) return gc_upto(av, H);
    1625       14273 :     if (groupelts_subgroup_isnormal(G, H))
    1626             :     {
    1627        1512 :       GEN C = groupelts_quotient(G, H);
    1628        1512 :       GEN Q = quotient_groupelts(C);
    1629        1512 :       GEN R = groupelts_to_group(Q);
    1630        1512 :       if (!R) return gc_NULL(av);
    1631        1512 :       return gc_GEN(av, quotient_subgroup_lift(C, H, R));
    1632             :     }
    1633             :   }
    1634         679 :   if (n==12 && l==9 && ord[2]==2 && ord[3]==2 && ord[5]==3)
    1635         602 :     return gc_GEN(av,
    1636         301 :       mkvec2(mkvec3(gel(G,cyc[2]), gel(G,cyc[3]), gel(G,cyc[5])), mkvecsmall3(2,2,3)));
    1637         378 :   if (n==24 && l==18 && ord[11]==3 && ord[15]==4 && ord[16]==4)
    1638             :   {
    1639         350 :     GEN t21 = perm_sqr(gel(G,cyc[15]));
    1640         350 :     GEN t22 = perm_sqr(gel(G,cyc[16]));
    1641         350 :     GEN s = perm_mul(t22, gel(G,cyc[15]));
    1642         700 :     return gc_GEN(av,
    1643         350 :       mkvec2(mkvec4(t21,t22, gel(G,cyc[11]), s), mkvecsmall4(2,2,3,2)));
    1644             :   }
    1645          28 :   if (n==36 && l==24 && ord[11]==3 && ord[15]==4)
    1646             :   {
    1647           7 :     GEN t1 = gel(G,cyc[11]), t3 = gel(G,cyc[15]);
    1648           7 :     return gc_GEN(av,
    1649             :       mkvec2(mkvec3(perm_conj(t3, t1), t1, t3), mkvecsmall3(3,3,4)));
    1650             :   }
    1651          21 :   return gc_NULL(av);
    1652             : }
    1653             : 
    1654             : static GEN
    1655        1176 : subg_get_gen(GEN subg) {  return gel(subg, 1); }
    1656             : 
    1657             : static GEN
    1658        8694 : subg_get_set(GEN subg) {  return gel(subg, 2); }
    1659             : 
    1660             : static GEN
    1661         812 : groupelt_subg_normalize(GEN elt, GEN subg, GEN cyc)
    1662             : {
    1663         812 :   GEN gen = subg_get_gen(subg), set =  subg_get_set(subg);
    1664         812 :   long i, j, u, n = lg(elt)-1, lgen = lg(gen);
    1665         812 :   GEN b = F2v_copy(cyc), res = zero_F2v(n);
    1666       49532 :   for(i = 1; i <= n; i++)
    1667             :   {
    1668             :     GEN g;
    1669       48720 :     if (!F2v_coeff(b, i)) continue;
    1670       22386 :     g = gel(elt,i);
    1671      763532 :     for(u=1; u<=n; u++)
    1672      763532 :       if (g[u]==1) break;
    1673       25172 :     for(j=1; j<lgen; j++)
    1674             :     {
    1675       23786 :       GEN h = gel(elt,gen[j]);
    1676       23786 :       if (!F2v_coeff(set,g[h[u]])) break;
    1677             :     }
    1678       22386 :     if (j < lgen) continue;
    1679        1386 :     F2v_set(res,i);
    1680       84546 :     for(j=1; j <= n; j++)
    1681       83160 :       if (F2v_coeff(set, j))
    1682        6720 :         F2v_clear(b,g[gel(elt,j)[1]]);
    1683             :   }
    1684         812 :   return res;
    1685             : }
    1686             : 
    1687             : static GEN
    1688          14 : triv_subg(GEN elt)
    1689             : {
    1690          14 :   GEN v = cgetg(3, t_VEC);
    1691          14 :   gel(v,1) = cgetg(1,t_VECSMALL);
    1692          14 :   gel(v,2) = zero_F2v(lg(elt)-1);
    1693          14 :   F2v_set(gel(v,2),1);
    1694          14 :   return v;
    1695             : }
    1696             : 
    1697             : static GEN
    1698         364 : subg_extend(GEN U, long e, long o, GEN elt)
    1699             : {
    1700         364 :   long i, j, n = lg(elt)-1;
    1701         364 :   GEN g = gel(elt, e);
    1702         364 :   GEN gen = vecsmall_append(subg_get_gen(U), e);
    1703         364 :   GEN set = subg_get_set(U);
    1704         364 :   GEN Vset = zv_copy(set);
    1705       22204 :   for(i = 1; i <= n; i++)
    1706       21840 :     if (F2v_coeff(set, i))
    1707             :     {
    1708        1260 :       long h = gel(elt, i)[1];
    1709        2800 :       for(j = 1; j < o; j++)
    1710             :       {
    1711        1540 :         h = g[h];
    1712        1540 :         F2v_set(Vset, h);
    1713             :       }
    1714             :     }
    1715         364 :   return mkvec2(gen, Vset);
    1716             : }
    1717             : 
    1718             : static GEN
    1719         434 : cyclic_subg(long e, long o, GEN elt)
    1720             : {
    1721         434 :   long j, n = lg(elt)-1, h = 1;
    1722         434 :   GEN g = gel(elt, e);
    1723         434 :   GEN gen = mkvecsmall(e);
    1724         434 :   GEN set = zero_F2v(n);
    1725         434 :   F2v_set(set,1);
    1726        1260 :   for(j = 1; j < o; j++)
    1727             :   {
    1728         826 :     h = g[h];
    1729         826 :     F2v_set(set, h);
    1730             :   }
    1731         434 :   return mkvec2(gen, set);
    1732             : }
    1733             : 
    1734             : static GEN
    1735          14 : groupelts_to_regular(GEN elt)
    1736             : {
    1737          14 :   long i, j, n = lg(elt)-1;
    1738          14 :   GEN V = cgetg(n+1,t_VEC);
    1739         854 :   for (i=1; i<=n; i++)
    1740             :   {
    1741         840 :     pari_sp av = avma;
    1742         840 :     GEN g = gel(elt, i);
    1743         840 :     GEN W = cgetg(n+1,t_VEC);
    1744       51240 :     for(j=1; j<=n; j++)
    1745       50400 :       gel(W,j) = perm_mul(g, gel(elt,j));
    1746         840 :     gel(V, i) = gc_leaf(av,vecvecsmall_indexsort(W));
    1747             :   }
    1748          14 :   vecvecsmall_sort_inplace(V, NULL);
    1749          14 :   return V;
    1750             : }
    1751             : 
    1752             : static long
    1753         434 : groupelts_pow(GEN elt, long j, long n)
    1754             : {
    1755         434 :   GEN g = gel(elt,j);
    1756         434 :   long i, h = 1;
    1757        1694 :   for (i=1; i<=n; i++)
    1758        1260 :     h = g[h];
    1759         434 :   return h;
    1760             : }
    1761             : 
    1762             : static GEN
    1763          14 : groupelts_cyclic_primepow(GEN elt, GEN *pt_pr, GEN *pt_po)
    1764             : {
    1765          14 :   GEN R = groupelts_cyclic_subgroups(elt);
    1766          14 :   GEN gen = gel(R,1), ord = gel(R,2);
    1767          14 :   long i, n = lg(elt)-1, l = lg(gen);
    1768          14 :   GEN set = zero_F2v(n);
    1769          14 :   GEN pr  = zero_Flv(n);
    1770          14 :   GEN po  = zero_Flv(n);
    1771         462 :   for (i = 1; i < l; i++)
    1772             :   {
    1773         448 :     long h = gen[i];
    1774             :     ulong p;
    1775         448 :     if (uisprimepower(ord[i], &p))
    1776             :     {
    1777         434 :       F2v_set(set, h);
    1778         434 :       uel(pr,h) = p;
    1779         434 :       po[h] = groupelts_pow(elt, h, p);
    1780             :     }
    1781             :   }
    1782          14 :   *pt_pr = pr; *pt_po = po;
    1783          14 :   return set;
    1784             : }
    1785             : 
    1786             : static GEN
    1787       50400 : perm_bracket(GEN p, GEN q)
    1788             : {
    1789       50400 :   return perm_mul(perm_mul(p,q), perm_inv(perm_mul(q,p)));
    1790             : }
    1791             : 
    1792             : static GEN
    1793         826 : set_groupelts(GEN S, GEN x)
    1794             : {
    1795         826 :   long i, n = F2v_hamming(x), k=1, m = x[1];
    1796         826 :   GEN v = cgetg(n+1, t_VEC);
    1797       50386 :   for (i=1; i<=m; i++)
    1798       49560 :     if (F2v_coeff(x,i))
    1799        4914 :       gel(v,k++) = gel(S,i);
    1800         826 :   return v;
    1801             : }
    1802             : 
    1803             : static GEN
    1804          14 : set_idx(GEN x)
    1805             : {
    1806          14 :   long i, n = F2v_hamming(x), k=1, m = x[1];
    1807          14 :   GEN v = cgetg(n+1, t_VECSMALL);
    1808         854 :   for (i=1; i<=m; i++)
    1809         840 :     if (F2v_coeff(x,i))
    1810         840 :       uel(v,k++) = i;
    1811          14 :   return v;
    1812             : }
    1813             : 
    1814             : static GEN
    1815          14 : set_derived(GEN set, GEN elts)
    1816             : {
    1817          14 :   long i, j, l = lg(elts);
    1818          14 :   GEN V = zero_F2v(l-1);
    1819         854 :   for(i = 1; i < l; i++)
    1820         840 :     if (F2v_coeff(set, i))
    1821       51240 :       for(j = 1; j < l; j++)
    1822       50400 :         if (F2v_coeff(set, j))
    1823       50400 :           F2v_set(V, perm_bracket(gel(elts,i),gel(elts,j))[1]);
    1824          14 :   return V;
    1825             : }
    1826             : 
    1827             : static GEN
    1828          14 : groupelts_residuum(GEN elts)
    1829             : {
    1830          14 :   pari_sp av = avma;
    1831          14 :   long o = lg(elts)-1, oo;
    1832          14 :   GEN set = const_F2v(o);
    1833             :   do
    1834             :   {
    1835          14 :     oo = o;
    1836          14 :     set = set_derived(set, elts);
    1837          14 :     o = F2v_hamming(set);
    1838          14 :   } while (o > 1 && o < oo);
    1839          14 :   if (o==1) return NULL;
    1840          14 :   return gc_GEN(av,mkvec2(set_idx(set), set));
    1841             : }
    1842             : 
    1843             : static GEN
    1844          14 : all_cyclic_subg(GEN pr, GEN po, GEN elt)
    1845             : {
    1846          14 :   long i, n = lg(pr)-1, m = 0, k = 1;
    1847             :   GEN W;
    1848         854 :   for (i=1; i <= n; i++)
    1849         840 :     m += po[i]==1;
    1850          14 :   W = cgetg(m+1, t_VEC);
    1851         854 :   for (i=1; i <= n; i++)
    1852         840 :     if (po[i]==1)
    1853         434 :       gel(W, k++) = cyclic_subg(i, pr[i], elt);
    1854          14 :   return W;
    1855             : }
    1856             : 
    1857             : static GEN
    1858          14 : groupelts_subgroups_raw(GEN elts)
    1859             : {
    1860          14 :   pari_sp av = avma;
    1861          14 :   GEN elt = groupelts_to_regular(elts);
    1862          14 :   GEN pr, po, cyc = groupelts_cyclic_primepow(elt, &pr, &po);
    1863          14 :   long n = lg(elt)-1;
    1864          14 :   long i, j, nS = 1;
    1865          14 :   GEN S, L, R = NULL;
    1866          14 :   S = cgetg(1+bigomegau(n)+1, t_VEC);
    1867          14 :   gel(S, nS++) = mkvec(triv_subg(elt));
    1868          14 :   gel(S, nS++) = L = all_cyclic_subg(pr, po, elt);
    1869          14 :   if (DEBUGLEVEL) err_printf("subgroups: level %ld: %ld\n",nS-1,lg(L)-1);
    1870          70 :   while (lg(L) > 1)
    1871             :   {
    1872          56 :     pari_sp av2 = avma;
    1873          56 :     long nW = 1, lL = lg(L);
    1874          56 :     long ng = n;
    1875          56 :     GEN W = cgetg(1+ng, t_VEC);
    1876         868 :     for (i=1; i<lL; i++)
    1877             :     {
    1878         812 :       GEN U = gel(L, i), set = subg_get_set(U);
    1879         812 :       GEN G = groupelt_subg_normalize(elt, U, cyc);
    1880        7154 :       for (j=1; j<nW; j++)
    1881             :       {
    1882        6342 :         GEN Wj = subg_get_set(gel(W, j));
    1883        6342 :         if (F2v_subset(set, Wj))
    1884         728 :           F2v_negimply_inplace(G, Wj);
    1885             :       }
    1886       49532 :       for (j=1; j<=n; j++)
    1887       48720 :         if(F2v_coeff(G,j))
    1888             :         {
    1889         770 :           long p = pr[j];
    1890         770 :           if (F2v_coeff(set, j)) continue;
    1891         364 :           if (F2v_coeff(set, po[j]))
    1892             :           {
    1893         364 :             GEN U2 = subg_extend(U, j, p, elt);
    1894         364 :             F2v_negimply_inplace(G, subg_get_set(U2));
    1895         364 :             if (nW > ng) { ng<<=1; W = vec_lengthen(W, ng); }
    1896         364 :             gel(W, nW++) = U2;
    1897             :           }
    1898             :         }
    1899             :     }
    1900          56 :     setlg(W, nW);
    1901          56 :     L = W;
    1902          56 :     if (nW > 1) gel(S, nS++) = L = gc_GEN(av2, W);
    1903          56 :     if (DEBUGLEVEL) err_printf("subgroups: level %ld: %ld\n",nS-1,nW-1);
    1904          56 :     if (lg(L)==1 && !R)
    1905             :     {
    1906          14 :       R = groupelts_residuum(elt);
    1907          14 :       if (!R) break;
    1908          14 :       gel(S, nS++) = L = mkvec(R);
    1909             :     }
    1910             :   }
    1911          14 :   setlg(S, nS);
    1912          14 :   return gc_GEN(av, shallowconcat1(S));
    1913             : }
    1914             : 
    1915             : static GEN
    1916          14 : subg_to_elts(GEN S, GEN x)
    1917         840 : { pari_APPLY_type(t_VEC, set_groupelts(S, gmael(x,i,2))); }
    1918             : 
    1919             : GEN
    1920          14 : groupelts_solvablesubgroups(GEN G)
    1921             : {
    1922          14 :   pari_sp av = avma;
    1923          14 :   GEN S = vecvecsmall_sort(checkgroupelts(G));
    1924          14 :   GEN L = groupelts_subgroups_raw(S);
    1925          14 :   return gc_GEN(av, subg_to_elts(S, L));
    1926             : }

Generated by: LCOV version 1.16