3
3
An implementation of the algorithm described in
4
4
"Kedlaya's Algorithm in Larger Characteristic"
5
5
6
+ version 1.1
7
+
6
8
Copyright (C) 2007, David Harvey
7
9
8
10
This program is free software; you can redistribute it and/or modify
@@ -1488,6 +1490,77 @@ int padic_xgcd(ZZ_pX& a, ZZ_pX& b, const ZZ_pX& f, const ZZ_pX& g,
1488
1490
1489
1491
1490
1492
1493
+ /*
1494
+ Given a matrix A over Z/p^N that is invertible mod p, this routine computes
1495
+ the inverse B = A^(-1) over Z/p^N.
1496
+
1497
+ PRECONDITIONS:
1498
+ The current NTL modulus should be p^N, and should be the one used to create
1499
+ the matrix A.
1500
+
1501
+ NOTE:
1502
+ It's not clear to me (from the code or the documentation) whether NTL's
1503
+ matrix inversion is guaranteed to work over a non-field. So I implemented
1504
+ this one just in case.
1505
+
1506
+ */
1507
+ void padic_invert_matrix (mat_ZZ_p& B, const mat_ZZ_p& A, const ZZ& p, int N)
1508
+ {
1509
+ ZZ_pContext modulus;
1510
+ modulus.save ();
1511
+
1512
+ int n = A.NumRows ();
1513
+
1514
+ // =================================================
1515
+ // First do it mod p using NTL matrix inverse
1516
+
1517
+ // lift to Z
1518
+ mat_ZZ A_lift;
1519
+ A_lift.SetDims (n, n);
1520
+ for (int y = 0 ; y < n; y++)
1521
+ for (int x = 0 ; x < n; x++)
1522
+ A_lift[y][x] = rep (A[y][x]);
1523
+
1524
+ // reduce down to Z/p
1525
+ ZZ_p::init (p);
1526
+ mat_ZZ_p A_red;
1527
+ A_red.SetDims (n, n);
1528
+ for (int y = 0 ; y < n; y++)
1529
+ for (int x = 0 ; x < n; x++)
1530
+ conv (A_red[y][x], A_lift[y][x]);
1531
+
1532
+ // invert matrix mod p
1533
+ mat_ZZ_p B_red;
1534
+ inv (B_red, A_red);
1535
+
1536
+ // lift result to Z
1537
+ mat_ZZ B_lift;
1538
+ B_lift.SetDims (n, n);
1539
+ for (int y = 0 ; y < n; y++)
1540
+ for (int x = 0 ; x < n; x++)
1541
+ B_lift[y][x] = rep (B_red[y][x]);
1542
+
1543
+ // reduce back to Z/p^N
1544
+ modulus.restore ();
1545
+ B.SetDims (n, n);
1546
+ for (int y = 0 ; y < n; y++)
1547
+ for (int x = 0 ; x < n; x++)
1548
+ conv (B[y][x], B_lift[y][x]);
1549
+
1550
+ // =================================================
1551
+ // Now improve the approximation until we have enough precision
1552
+
1553
+ mat_ZZ_p two;
1554
+ ident (two, n);
1555
+ two *= 2 ;
1556
+
1557
+ for (int prec = 1 ; prec < N; prec *= 2 )
1558
+ // if BA = I + error, then ((2I - BA)B)A = (I - err)(I + err) = I - err^2
1559
+ B = (two - B*A) * B;
1560
+ }
1561
+
1562
+
1563
+
1491
1564
/*
1492
1565
The main function exported from this module. See frobenius.h for information.
1493
1566
*/
@@ -1510,6 +1583,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1510
1583
modulus_caller.save ();
1511
1584
1512
1585
// Create moduli for working mod p^N and mod p^(N+1)
1586
+
1513
1587
ZZ_pContext modulus0, modulus1;
1514
1588
1515
1589
ZZ_p::init (power (p, N));
@@ -1520,6 +1594,12 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1520
1594
// =========================================================================
1521
1595
// Compute vertical reduction matrix M_V(t) and denominator D_V(t).
1522
1596
1597
+ // If N > 1 we need to do this to precision p^(N+1).
1598
+ // If N = 1 we can get away with precision N, since the last reduction
1599
+ // of length (p-1)/2 doesn't involve any divisions by p.
1600
+ ZZ_pContext modulusV = (N == 1 ) ? modulus0 : modulus1;
1601
+ modulusV.restore ();
1602
+
1523
1603
// To compute the vertical reduction matrices, for each 0 <= i < 2g, we need
1524
1604
// to find R_i(x) and S_i(x) satisfying x^i = R_i(x) Q(x) + S_i(x) Q'(x).
1525
1605
vector<ZZ_pX> R, S;
@@ -1601,6 +1681,18 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1601
1681
}
1602
1682
}
1603
1683
1684
+ // Compute inverse of the vandermonde matrix that will be used in the
1685
+ // horizontal reduction phase
1686
+ mat_ZZ_p vand_in, vand;
1687
+ vand_in.SetDims (N, N);
1688
+ for (int y = 1 ; y <= N; y++)
1689
+ {
1690
+ vand_in[y-1 ][0 ] = 1 ;
1691
+ for (int x = 1 ; x < N; x++)
1692
+ vand_in[y-1 ][x] = vand_in[y-1 ][x-1 ] * y;
1693
+ }
1694
+ padic_invert_matrix (vand, vand_in, p, N);
1695
+
1604
1696
// =========================================================================
1605
1697
// Compute B_{j, r} coefficients.
1606
1698
// These are done to precision p^(N+1).
@@ -1652,18 +1744,71 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1652
1744
for (int j = 0 ; j < N; j++)
1653
1745
{
1654
1746
// Compute the transition matrices, mod p^N, between the indices
1655
- // kp-2g-2 and kp, for each k.
1747
+ // kp-2g-2 and kp, for each k. We compute at most N matrices (the others
1748
+ // will be deduced more efficiently using the vandermonde matrix below)
1656
1749
modulus0.restore ();
1657
1750
vector<ZZ> s;
1658
- for (int k = 0 ; k < (2 *g+1 )*(j+1 ); k++)
1751
+ int L = (2 *g+1 )*(j+1 ) - 1 ;
1752
+ int L_effective = min (L, N);
1753
+ for (int k = 0 ; k < L_effective; k++)
1659
1754
{
1660
1755
s.push_back (k*p);
1661
1756
s.push_back ((k+1 )*p - 2 *g - 2 );
1662
1757
}
1663
1758
vector<mat_ZZ_p> MH, DH;
1759
+ MH.reserve (L);
1760
+ DH.reserve (L);
1664
1761
large_interval_products_wrapper (MH, MH0[j], MH1[j], s);
1665
1762
large_interval_products_wrapper (DH, DH0[j], DH1[j], s);
1666
1763
1764
+ // Use the vandermonde matrix to extend all the way up to L if necessary.
1765
+ if (L > N)
1766
+ {
1767
+ // First compute X[r] = F^{(r)}(0) p^r / r! for r = 0, ..., N-1,
1768
+ // where F is the matrix corresponding to M as described in the paper;
1769
+ // and do the same for Y corresponding to the denominator D.
1770
+ vector<mat_ZZ_p> X (N);
1771
+ vector<ZZ_p> Y (N);
1772
+ for (int r = 0 ; r < N; r++)
1773
+ {
1774
+ X[r].SetDims (2 *g+1 , 2 *g+1 );
1775
+ for (int h = 0 ; h < N; h++)
1776
+ {
1777
+ ZZ_p& v = vand[r][h];
1778
+
1779
+ for (int y = 0 ; y < 2 *g+1 ; y++)
1780
+ for (int x = 0 ; x < 2 *g+1 ; x++)
1781
+ X[r][y][x] += v * MH[h][y][x];
1782
+
1783
+ Y[r] += v * DH[h][0 ][0 ];
1784
+ }
1785
+ }
1786
+
1787
+ // Now use those taylor coefficients to get the remaining MH's
1788
+ // and DH's.
1789
+ MH.resize (L);
1790
+ DH.resize (L);
1791
+ for (int k = N; k < L; k++)
1792
+ {
1793
+ MH[k].SetDims (2 *g+1 , 2 *g+1 );
1794
+ DH[k].SetDims (1 , 1 );
1795
+
1796
+ // this is actually a power of k+1, since the indices into
1797
+ // MH and DH are one-off from what's written in the paper
1798
+ ZZ_p k_pow;
1799
+ k_pow = 1 ;
1800
+
1801
+ for (int h = 0 ; h < N; h++, k_pow *= (k+1 ))
1802
+ {
1803
+ for (int y = 0 ; y < 2 *g+1 ; y++)
1804
+ for (int x = 0 ; x < 2 *g+1 ; x++)
1805
+ MH[k][y][x] += k_pow * X[h][y][x];
1806
+
1807
+ DH[k][0 ][0 ] += k_pow * Y[h];
1808
+ }
1809
+ }
1810
+ }
1811
+
1667
1812
// Divide out each MH[k] by DH[k].
1668
1813
for (int k = 0 ; k < MH.size (); k++)
1669
1814
{
@@ -1706,7 +1851,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1706
1851
sum[0 ] = 0 ;
1707
1852
1708
1853
// add in contribution from c (these follow from the explicit
1709
- // formulae for the horizontal reductions;
1854
+ // formulae for the horizontal reductions)
1710
1855
ZZ s = k*p - u;
1711
1856
c /= to_ZZ_p ((2 *g+1 )*tt - 2 *s);
1712
1857
for (int m = 0 ; m <= 2 *g; m++)
@@ -1780,6 +1925,20 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1780
1925
}
1781
1926
}
1782
1927
1928
+ if (N == 1 )
1929
+ {
1930
+ // If N == 1, then the vertical matrices are stored at precision 1
1931
+ // (instead of at N+1), so we reduce "reduced" to precision 1 here.
1932
+ modulus0.restore ();
1933
+ vector<vector<vec_ZZ_p> > reduced_temp (N, vector<vec_ZZ_p>(2 *g));
1934
+ for (int j = 0 ; j < N; j++)
1935
+ for (int i = 0 ; i < 2 *g; i++)
1936
+ change_vec_modulus (reduced_temp[j][i], modulus0,
1937
+ reduced[j][i], modulus1);
1938
+
1939
+ reduced.swap (reduced_temp);
1940
+ }
1941
+
1783
1942
// =========================================================================
1784
1943
// Vertical reductions.
1785
1944
@@ -1793,6 +1952,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
1793
1952
s.push_back (s.back ());
1794
1953
s.push_back (s.back () + p);
1795
1954
}
1955
+ modulusV.restore ();
1796
1956
vector<mat_ZZ_p> MV, DV;
1797
1957
large_interval_products_wrapper (MV, MV0, MV1, s);
1798
1958
large_interval_products_wrapper (DV, DV0, DV1, s);
0 commit comments