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 - bnfunits.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 97.0 % 232 225
Test Date: 2026-07-22 22:45:42 Functions: 100.0 % 14 14
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2020  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              : #include "pari.h"
      15              : #include "paripriv.h"
      16              : 
      17              : #define DEBUGLEVEL DEBUGLEVEL_bnf
      18              : 
      19              : /* if x a famat, assume it is a true unit (very costly to check even that
      20              :  * it's an algebraic integer) */
      21              : GEN
      22         1645 : bnfisunit(GEN bnf, GEN x)
      23              : {
      24         1645 :   long tx = typ(x), i, r1, RU, e, n, prec;
      25         1645 :   pari_sp av = avma;
      26              :   GEN t, logunit, ex, nf, pi2_sur_w, rx, emb, arg;
      27              : 
      28         1645 :   bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
      29         1645 :   RU = lg(bnf_get_logfu(bnf));
      30         1645 :   n = bnf_get_tuN(bnf); /* # { roots of 1 } */
      31         1645 :   if (tx == t_MAT)
      32              :   { /* famat, assumed OK */
      33         1309 :     if (lg(x) != 3) pari_err_TYPE("bnfisunit [not a factorization]", x);
      34              :   } else {
      35          336 :     x = nf_to_scalar_or_basis(nf,x);
      36          336 :     if (typ(x) != t_COL)
      37              :     { /* rational unit ? */
      38              :       GEN v;
      39              :       long s;
      40          140 :       if (typ(x) != t_INT || !is_pm1(x)) return cgetg(1,t_COL);
      41          133 :       s = signe(x); set_avma(av); v = zerocol(RU);
      42          133 :       gel(v,RU) = utoi((s > 0)? 0: n>>1);
      43          133 :       return v;
      44              :     }
      45          196 :     if (!isint1(Q_denom(x))) retgc_const(av, cgetg(1, t_COL));
      46              :   }
      47              : 
      48         1505 :   r1 = nf_get_r1(nf);
      49         1505 :   prec = nf_get_prec(nf);
      50         1505 :   for (i = 1;; i++)
      51            0 :   {
      52              :     GEN rlog;
      53         1505 :     nf = bnf_get_nf(bnf);
      54         1505 :     logunit = bnf_get_logfu(bnf);
      55         1505 :     rlog = real_i(logunit);
      56         1505 :     rx = nflogembed(nf,x,&emb, prec);
      57         1505 :     if (rx)
      58              :     {
      59         1505 :       GEN logN = RgV_sum(rx); /* log(Nx), should be ~ 0 */
      60         1505 :       if (gexpo(logN) > -20)
      61              :       { /* precision problem ? */
      62           14 :         if (typ(logN) != t_REAL) retgc_const(av, cgetg(1, t_COL)); /*no*/
      63           28 :         if (i == 1 && typ(x) != t_MAT &&
      64           28 :             !is_pm1(nfnorm(nf, x))) retgc_const(av, cgetg(1, t_COL));
      65              :       }
      66              :       else
      67              :       {
      68          504 :         ex = RU == 1? cgetg(1,t_COL)
      69         1491 :                     : RgM_solve(rlog, rx); /* ~ fundamental units exponents */
      70         1491 :         if (ex) { ex = grndtoi(ex, &e); if (e < -4) break; }
      71              :       }
      72              :     }
      73            0 :     if (i == 1)
      74            0 :       prec = nbits2prec(gexpo(x) + 128);
      75              :     else
      76              :     {
      77            0 :       if (i > 4) pari_err_PREC("bnfisunit");
      78            0 :       prec = precdbl(prec);
      79              :     }
      80            0 :     if (DEBUGLEVEL) pari_warn(warnprec,"bnfisunit",prec);
      81            0 :     bnf = bnfnewprec_shallow(bnf, prec);
      82              :   }
      83              :   /* choose a large embedding => small relative error */
      84         2033 :   for (i = 1; i < RU; i++)
      85         1394 :     if (signe(gel(rx,i)) > -1) break;
      86         1491 :   if (RU == 1) t = gen_0;
      87              :   else
      88              :   {
      89          987 :     t = imag_i( row_i(logunit,i, 1,RU-1) );
      90          987 :     t = RgV_dotproduct(t, ex);
      91          987 :     if (i > r1) t = gmul2n(t, -1);
      92              :   }
      93         1491 :   if (typ(emb) != t_MAT) arg = garg(gel(emb,i), prec);
      94              :   else
      95              :   {
      96         1309 :     GEN p = gel(emb,1), e = gel(emb,2);
      97         1309 :     long j, l = lg(p);
      98         1309 :     arg = NULL;
      99        62132 :     for (j = 1; j < l; j++)
     100              :     {
     101        60823 :       GEN a = gmul(gel(e,j), garg(gel(gel(p,j),i), prec));
     102        60823 :       arg = arg? gadd(arg, a): a;
     103              :     }
     104              :   }
     105         1491 :   t = gsub(arg, t); /* = arg(the missing root of 1) */
     106         1491 :   pi2_sur_w = divru(mppi(prec), n>>1); /* 2pi / n */
     107         1491 :   e = umodiu(roundr(divrr(t, pi2_sur_w)), n);
     108         1491 :   if (n > 2)
     109              :   {
     110            7 :     GEN z = algtobasis(nf, bnf_get_tuU(bnf)); /* primitive root of 1 */
     111            7 :     GEN ro = RgV_dotproduct(row(nf_get_M(nf), i), z);
     112            7 :     GEN p2 = roundr(divrr(garg(ro, prec), pi2_sur_w));
     113            7 :     e *= Fl_inv(umodiu(p2,n), n);
     114            7 :     e %= n;
     115              :   }
     116         1491 :   gel(ex,RU) = utoi(e); setlg(ex, RU+1); return gc_GEN(av, ex);
     117              : }
     118              : 
     119              : /* split M a square ZM in HNF as [H, B; 0, Id], H in HNF without 1-eigenvalue */
     120              : static GEN
     121         1015 : hnfsplit(GEN M, GEN *pB)
     122              : {
     123         1015 :   long i, l = lg(M);
     124         3531 :   for (i = l-1; i; i--)
     125         3230 :     if (!equali1(gcoeff(M,i,i))) break;
     126         1015 :   if (!i) { *pB = zeromat(0, l-1); return cgetg(1, t_MAT); }
     127          714 :   *pB = matslice(M, 1, i, i+1, l-1); return matslice(M, 1, i, 1, i);
     128              : }
     129              : 
     130              : /* S a list of prime ideal in idealprimedec format. If pH != NULL, set it to
     131              :  * the HNF of the S-class group and return bnfsunit, else return bnfunits */
     132              : static GEN
     133         1463 : bnfsunit_i(GEN bnf, GEN S, GEN *pH, GEN *pA, GEN *pden)
     134              : {
     135         1463 :   long FLAG, i, lS = lg(S);
     136              :   GEN M, U1, U2, U, V, H, Sunit, B, g;
     137              : 
     138         1463 :   if (!is_vec_t(typ(S))) pari_err_TYPE("bnfsunit",S);
     139         1463 :   bnf = checkbnf(bnf);
     140         1463 :   if (lS == 1)
     141              :   {
     142          448 :     *pA = cgetg(1,t_MAT);
     143          448 :     *pden = gen_1; return cgetg(1,t_VEC);
     144              :   }
     145         1015 :   M = cgetg(lS,t_MAT); /* relation matrix for the S class group */
     146         1015 :   g = cgetg(lS,t_MAT); /* principal part */
     147         1015 :   FLAG = pH ? 0: nf_GENMAT;
     148         6111 :   for (i = 1; i < lS; i++)
     149              :   {
     150         5096 :     GEN pr = gel(S,i);
     151         5096 :     checkprid(pr);
     152         5096 :     if (pH)
     153         1855 :       gel(M,i) = isprincipal(bnf, pr);
     154              :     else
     155              :     {
     156         3241 :       GEN v = bnfisprincipal0(bnf, pr, FLAG);
     157         3241 :       gel(M,i) = gel(v,1);
     158         3241 :       gel(g,i) = gel(v,2);
     159              :     }
     160              :   }
     161              :   /* S class group and S units, use ZM_hnflll to get small 'U' */
     162         1015 :   M = shallowconcat(M, diagonal_shallow(bnf_get_cyc(bnf)));
     163         1015 :   H = ZM_hnflll(M, &U, 1); setlg(U, lS); if (pH) *pH = H;
     164         1015 :   U1 = rowslice(U,1, lS-1);
     165         1015 :   U2 = rowslice(U,lS, lg(M)-1); /* (M | cyc) [U1; U2] = 0 */
     166         1015 :   H = ZM_hnflll(U1, pH? NULL: &V, 0);
     167              :  /* U1 = upper left corner of U, invertible. S * U1 = principal ideals
     168              :   * whose generators generate the S-units */
     169         1015 :   H = hnfsplit(H, &B);
     170              :  /*                     [ H B  ]            [ H^-1   - H^-1 B ]
     171              :   * U1 * V = HNF(U1) =  [ 0 Id ], inverse = [  0         Id   ]
     172              :   * S * HNF(U1) = integral generators for S-units = Sunit */
     173         1015 :   Sunit = cgetg(lS, t_VEC);
     174         1015 :   if (pH)
     175              :   {
     176          168 :     long nH = lg(H) - 1;
     177          168 :     FLAG = nf_FORCE | nf_GEN;
     178         2023 :     for (i = 1; i < lS; i++)
     179              :     {
     180         1855 :       GEN C = NULL, E;
     181         1855 :       if (i <= nH) E = gel(H,i); else { C = gel(S,i), E = gel(B,i-nH); }
     182         1855 :       gel(Sunit,i) = gel(isprincipalfact(bnf, C, S, E, FLAG), 2);
     183              :     }
     184              :   }
     185              :   else
     186              :   {
     187          847 :     GEN cycgen = bnf_build_cycgen(bnf);
     188          847 :     U1 = ZM_mul(U1, V);
     189          847 :     U2 = ZM_mul(U2, V);
     190          847 :     FLAG = nf_FORCE | nf_GENMAT;
     191         4088 :     for (i = 1; i < lS; i++)
     192              :     {
     193         3241 :       GEN a = famatV_factorback(g, gel(U1,i));
     194         3241 :       GEN b = famatV_factorback(cycgen, ZC_neg(gel(U2,i)));
     195         3241 :       gel(Sunit,i) = famat_reduce(famat_mul(a, b));
     196              :     }
     197              :   }
     198         1015 :   H = ZM_inv(H, pden);
     199         1015 :   *pA = shallowconcat(H, ZM_neg(ZM_mul(H,B))); /* top inverse * den */
     200         1015 :   return Sunit;
     201              : }
     202              : GEN
     203          175 : bnfsunit(GEN bnf,GEN S,long prec)
     204              : {
     205          175 :   pari_sp av = avma;
     206          175 :   long i, l = lg(S);
     207          175 :   GEN v, R, nf, A, den, U, cl, H = NULL;
     208          175 :   bnf = checkbnf(bnf); nf = bnf_get_nf(bnf);
     209          175 :   v = cgetg(7, t_VEC);
     210          175 :   gel(v,1) = U = bnfsunit_i(bnf, S, &H, &A, &den);
     211          175 :   gel(v,2) = mkvec2(A, den);
     212          175 :   gel(v,3) = cgetg(1,t_VEC); /* dummy */
     213          175 :   R = bnf_get_reg(bnf);
     214          175 :   cl = bnf_get_clgp(bnf);
     215          175 :   if (l != 1)
     216              :   {
     217          168 :     GEN E, u, A, G = bnf_get_gen(bnf), D = ZM_snf_group(H,NULL,&u);
     218          168 :     GEN h = ZV_prod(D), P = cgetg(l, t_VEC);
     219          168 :     long lD = lg(D);
     220          168 :     A = cgetg(lD, t_VEC);
     221          189 :     for(i = 1; i < lD; i++) gel(A,i) = idealfactorback(nf, G, gel(u,i), 1);
     222          168 :     cl = mkvec3(h, D, A);
     223              :     /* R(S)/R = h * prod log N(S[i]) = h prod f(S[i]) prod log(S[i].p)*/
     224         2023 :     for (i = 1; i < l; i++)
     225              :     {
     226         1855 :       GEN pr = gel(S,i);
     227         1855 :       long f = pr_get_f(pr);
     228         1855 :       gel(P,i) = pr_get_p(pr); if (f != 1) h = muliu(h, f);
     229         1855 :       gel(U,i) = nf_to_scalar_or_alg(nf, gel(U,i));
     230              :     }
     231              :     /* h = #Cl(K) prod_i f(S[i]) */
     232          168 :     P = vec_reduce(P, &E);
     233          168 :     P = factorback2(glog(P, prec), E);
     234          168 :     R = typ(R)==t_INT? P: mulrr(R,P); /* = R * prod log(S[i].p) */
     235          168 :     R = mulir(h, R); /* S-regulator R(S) */
     236              :   }
     237          175 :   gel(v,4) = R;
     238          175 :   gel(v,5) = cl;
     239          175 :   gel(v,6) = S; return gc_GEN(av, v);
     240              : }
     241              : GEN
     242         1106 : bnfunits(GEN bnf, GEN S)
     243              : {
     244         1106 :   pari_sp av = avma;
     245              :   GEN A, den, U, fu, tu;
     246         1106 :   bnf = checkbnf(bnf);
     247         1106 :   U = bnfsunit_i(bnf, S? S: cgetg(1,t_VEC), NULL, &A, &den);
     248         1106 :   if (!S) S = cgetg(1,t_VEC);
     249         1106 :   fu = bnf_compactfu(bnf);
     250         1106 :   if (!fu)
     251              :   {
     252              :     long i, l;
     253          238 :     fu = bnf_has_fu(bnf); if (!fu) bnf_build_units(bnf);
     254          238 :     fu = shallowcopy(fu); l = lg(fu);
     255          693 :     for (i = 1; i < l; i++) gel(fu,i) = to_famat_shallow(gel(fu,i),gen_1);
     256              :   }
     257         1106 :   tu = nf_to_scalar_or_basis(bnf_get_nf(bnf), bnf_get_tuU(bnf));
     258         1106 :   U = shallowconcat(U, vec_append(fu, to_famat_shallow(tu,gen_1)));
     259         1106 :   return gc_GEN(av, mkvec4(U, S, A, den));
     260              : }
     261              : GEN
     262          182 : sunits_mod_units(GEN bnf, GEN S)
     263              : {
     264          182 :   pari_sp av = avma;
     265              :   GEN A, den;
     266          182 :   bnf = checkbnf(bnf);
     267          182 :   return gc_GEN(av, bnfsunit_i(bnf, S, NULL, &A, &den));
     268              : }
     269              : 
     270              : /* v_S(x), x in famat form */
     271              : static GEN
     272          105 : sunit_famat_val(GEN nf, GEN S, GEN x)
     273              : {
     274          105 :   long i, l = lg(S);
     275          105 :   GEN v = cgetg(l, t_VEC);
     276         1085 :   for (i = 1; i < l; i++) gel(v,i) = famat_nfvalrem(nf, x, gel(S,i), NULL);
     277          105 :   return v;
     278              : }
     279              : /* v_S(x) */
     280              : static GEN
     281         1498 : sunit_val(GEN nf, GEN S, GEN x)
     282              : {
     283         1498 :   long i, l = lg(S);
     284         1498 :   GEN v, Nx, dx, Ndx = gen_1;
     285         1498 :   if (isintzero(x)) return NULL;
     286         1498 :   v = zerocol(l-1);
     287         1498 :   x = Q_remove_denom(x, &dx);
     288         1498 :   Nx = idealnorm(nf, x);
     289         1498 :   if (dx) Ndx = powiu(dx, nf_get_degree(nf)); else if (is_pm1(Nx)) return v;
     290        37121 :   for (i = 1; i < l; i++)
     291              :   {
     292        35896 :     GEN P = gel(S,i), p = pr_get_p(P);
     293        35896 :     long f = pr_get_f(P), vn = 0, vd = 0;
     294        35896 :     if (dvdii(Nx, p))
     295              :     {
     296         2170 :       vn = nfval(nf, x, P);
     297         2170 :       if (vn) Nx = diviiexact(Nx, powiu(p, vn * f));
     298              :     }
     299        35896 :     if (dx && dvdii(dx, p))
     300              :     {
     301           35 :       vd = pr_get_e(P) * Z_pval(dx, p);
     302           35 :       if (vd) Ndx = diviiexact(Ndx, powiu(p, vd * f));
     303              :     }
     304        35896 :     vn -= vd; if (vn) gel(v,i) = stoi(vn);
     305              :   }
     306         1225 :   return is_pm1(Nx) && is_pm1(Ndx)? v: NULL;
     307              : }
     308              : 
     309              : /* if *px a famat, assume it's an S-unit */
     310              : static GEN
     311         1631 : make_unit(GEN nf, GEN U, GEN *px)
     312              : {
     313         1631 :   GEN den, v, w, A, gen = gel(U,1), S = gel(U,2), x = *px;
     314         1631 :   long cH, i, l = lg(S);
     315              : 
     316         1631 :   if (l == 1) return cgetg(1, t_COL);
     317         1603 :   A = gel(U,3); den = gel(U,4);
     318         1603 :   cH = nbrows(A);
     319         1603 :   if (typ(x) == t_MAT && lg(x) == 3)
     320          105 :     w = sunit_famat_val(nf, S, x); /* x = S v */
     321              :   else
     322              :   {
     323         1498 :     x = nf_to_scalar_or_basis(nf,x);
     324         1498 :     w = sunit_val(nf, S, x);
     325         1498 :     if (!w) return NULL;
     326              :   }
     327         1582 :   v = ZM_ZC_mul(A, w);
     328         1582 :   w += cH; w[0] = evaltyp(t_COL) | _evallg(lg(A) - cH);
     329         2810 :   if (!is_pm1(den)) for (i = 1; i <= cH; i++)
     330              :   {
     331              :     GEN r;
     332         1228 :     gel(v,i) = dvmdii(gel(v,i), den, &r);
     333         1228 :     if (r != gen_0) return NULL;
     334              :   }
     335         1582 :   v = shallowconcat(v, w); /* append bottom of w (= [0 Id] part) */
     336        41202 :   for (i = 1; i < l; i++)
     337              :   {
     338        39620 :     GEN e = gel(v,i);
     339        39620 :     if (signe(e)) x = famat_mulpow_shallow(x, gel(gen,i), negi(e));
     340              :   }
     341         1582 :   *px = x; return v;
     342              : }
     343              : 
     344              : static GEN
     345         1631 : bnfissunit_i(GEN bnf, GEN x, GEN U)
     346              : {
     347         1631 :   GEN w, nf, v = NULL;
     348         1631 :   bnf = checkbnf(bnf);
     349         1631 :   nf = bnf_get_nf(bnf);
     350         1631 :   if ( (w = make_unit(nf, U, &x)) ) v = bnfisunit(bnf, x);
     351         1631 :   if (!v || lg(v) == 1) return NULL;
     352         1596 :   return mkvec2(v, w);
     353              : }
     354              : static int
     355          126 : checkU(GEN U)
     356              : {
     357          126 :   if (typ(U) != t_VEC || lg(U) != 5) return 0;
     358          126 :   return typ(gel(U,1)) == t_VEC && is_vec_t(typ(gel(U,2)))
     359          252 :          && typ(gel(U,4))==t_INT;
     360              : }
     361              : GEN
     362          161 : bnfisunit0(GEN bnf, GEN x, GEN U)
     363              : {
     364          161 :   pari_sp av = avma;
     365              :   GEN z;
     366          161 :   if (!U) return bnfisunit(bnf, x);
     367          126 :   if (!checkU(U)) pari_err_TYPE("bnfisunit",U);
     368          126 :   z = bnfissunit_i(bnf, x, U);
     369          126 :   if (!z) retgc_const(av, cgetg(1, t_COL));
     370          112 :   return gc_GEN(av, shallowconcat(gel(z,2), gel(z,1)));
     371              : }
     372              : 
     373              : /* OBSOLETE */
     374              : static int
     375         1505 : checkbnfS_i(GEN v)
     376              : {
     377              :   GEN S, g, w;
     378         1505 :   if (typ(v) != t_VEC || lg(v) != 7) return 0;
     379         1505 :   g = gel(v,1); w = gel(v,2); S = gel(v,6);
     380         1505 :   if (typ(g) != t_VEC || !is_vec_t(typ(S)) || lg(S) != lg(g)) return 0;
     381         1505 :   return typ(w) == t_VEC && lg(w) == 3;
     382              : }
     383              : /* OBSOLETE */
     384              : GEN
     385         1505 : bnfissunit(GEN bnf, GEN bnfS, GEN x)
     386              : {
     387         1505 :   pari_sp av = avma;
     388              :   GEN z, U;
     389         1505 :   if (!checkbnfS_i(bnfS)) pari_err_TYPE("bnfissunit",bnfS);
     390         1505 :   U = mkvec4(gel(bnfS,1), gel(bnfS,6), gmael(bnfS,2,1), gmael(bnfS,2,2));
     391         1505 :   z = bnfissunit_i(bnf, x, U);
     392         1505 :   if (!z) retgc_const(av, cgetg(1, t_COL));
     393         1484 :   return gc_GEN(av, shallowconcat(gel(z,1), gel(z,2)));
     394              : }
        

Generated by: LCOV version 2.0-1