Skip to content

Commit ae45315

Browse files
committed
merge
2 parents 7d6ea7d + fa29614 commit ae45315

File tree

2 files changed

+165
-5
lines changed

2 files changed

+165
-5
lines changed

src/sage/schemes/hyperelliptic_curves/frobenius.pyx

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ def frobenius(p, N, Q):
9090
QQ = ZZX(Q)
9191

9292
bound = (len(Q) - 1) * (2*N - 1)
93-
if p < bound:
94-
raise ValueError, "In the current implementation, p must be at least (2g+1)(2N-1) = %s" % bound
93+
if p <= bound:
94+
raise ValueError, "In the current implementation, p must be greater than (2g+1)(2N-1) = %s" % bound
9595

9696
pp = ZZ(p)
9797

src/sage/schemes/hyperelliptic_curves/frobenius_cpp.cpp

+163-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
An implementation of the algorithm described in
44
"Kedlaya's Algorithm in Larger Characteristic"
55
6+
version 1.1
7+
68
Copyright (C) 2007, David Harvey
79
810
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,
14881490

14891491

14901492

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+
14911564
/*
14921565
The main function exported from this module. See frobenius.h for information.
14931566
*/
@@ -1510,6 +1583,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
15101583
modulus_caller.save();
15111584

15121585
// Create moduli for working mod p^N and mod p^(N+1)
1586+
15131587
ZZ_pContext modulus0, modulus1;
15141588

15151589
ZZ_p::init(power(p, N));
@@ -1520,6 +1594,12 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
15201594
// =========================================================================
15211595
// Compute vertical reduction matrix M_V(t) and denominator D_V(t).
15221596

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+
15231603
// To compute the vertical reduction matrices, for each 0 <= i < 2g, we need
15241604
// to find R_i(x) and S_i(x) satisfying x^i = R_i(x) Q(x) + S_i(x) Q'(x).
15251605
vector<ZZ_pX> R, S;
@@ -1601,6 +1681,18 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
16011681
}
16021682
}
16031683

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+
16041696
// =========================================================================
16051697
// Compute B_{j, r} coefficients.
16061698
// 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)
16521744
for (int j = 0; j < N; j++)
16531745
{
16541746
// 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)
16561749
modulus0.restore();
16571750
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++)
16591754
{
16601755
s.push_back(k*p);
16611756
s.push_back((k+1)*p - 2*g - 2);
16621757
}
16631758
vector<mat_ZZ_p> MH, DH;
1759+
MH.reserve(L);
1760+
DH.reserve(L);
16641761
large_interval_products_wrapper(MH, MH0[j], MH1[j], s);
16651762
large_interval_products_wrapper(DH, DH0[j], DH1[j], s);
16661763

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+
16671812
// Divide out each MH[k] by DH[k].
16681813
for (int k = 0; k < MH.size(); k++)
16691814
{
@@ -1706,7 +1851,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
17061851
sum[0] = 0;
17071852

17081853
// add in contribution from c (these follow from the explicit
1709-
// formulae for the horizontal reductions;
1854+
// formulae for the horizontal reductions)
17101855
ZZ s = k*p - u;
17111856
c /= to_ZZ_p((2*g+1)*tt - 2*s);
17121857
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)
17801925
}
17811926
}
17821927

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+
17831942
// =========================================================================
17841943
// Vertical reductions.
17851944

@@ -1793,6 +1952,7 @@ int frobenius(mat_ZZ& output, const ZZ& p, int N, const ZZX& Q)
17931952
s.push_back(s.back());
17941953
s.push_back(s.back() + p);
17951954
}
1955+
modulusV.restore();
17961956
vector<mat_ZZ_p> MV, DV;
17971957
large_interval_products_wrapper(MV, MV0, MV1, s);
17981958
large_interval_products_wrapper(DV, DV0, DV1, s);

0 commit comments

Comments
 (0)