static void MulAddDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { static ZZ t1, t2; mul(t1, x, c1); mul(t2, y, c2); add(t1, t1, t2); ExactDiv(c, t1, z); }
static void MulSubDiv(ZZ& c, const ZZ& c1, const ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 - y*c2)/z { static ZZ t1, t2; mul(t1, x, c1); mul(t2, y, c2); sub(t1, t1, t2); ExactDiv(c, t1, z); }
void inv(ZZ& d_out, mat_ZZ& x_out, const mat_ZZ& A, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (n == 0) { set(d_out); x_out.SetDims(0, 0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); mat_ZZ x(INIT_SIZE, n, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long gp_cnt = 0; long check = 0; mat_ZZ y; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { mat_zz_p xx; zz_p dd; inv(dd, xx, AA); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); if (IsDiag(y, n, d)) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); }
static long swap(long k, mat_ZZ& B, vec_long& P, vec_ZZ& D, vec_vec_ZZ& lam, mat_ZZ* U, long m, long verbose) // swaps vectors k-1 and k; assumes P(k-1) != 0 // returns 1 if vector k-1 need to be reduced after the swap... // this only occurs in 'case 2' when there are linear dependencies { long i, j; static ZZ t1, t2, t3, e, x, y; if (P(k) != 0) { swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); for (i = k+1; i <= m; i++) { MulAddDiv(t1, lam(i)(P(k)-1), lam(i)(P(k)), lam(k)(P(k)-1), D[P(k)-2], D[P(k)-1]); MulSubDiv(t2, lam(i)(P(k)-1), lam(i)(P(k)), D[P(k)], lam(k)(P(k)-1), D[P(k)-1]); lam(i)(P(k)-1) = t1; lam(i)(P(k)) = t2; } MulAddDiv(D[P(k)-1], D[P(k)], lam(k)(P(k)-1), D[P(k)-2], lam(k)(P(k)-1), D[P(k)-1]); return 0; } else if (!IsZero(lam(k)(P(k-1)))) { XGCD(e, x, y, lam(k)(P(k-1)), D[P(k-1)]); ExactDiv(t1, lam(k)(P(k-1)), e); ExactDiv(t2, D[P(k-1)], e); t3 = t2; negate(t2, t2); RowTransform(B(k-1), B(k), t1, t2, y, x); if (U) RowTransform((*U)(k-1), (*U)(k), t1, t2, y, x); for (j = 1; j <= k-2; j++) if (P(j) != 0) RowTransform(lam(k-1)(P(j)), lam(k)(P(j)), t1, t2, y, x); sqr(t2, t2); ExactDiv(D[P(k-1)], D[P(k-1)], t2); for (i = k+1; i <= m; i++) if (P(i) != 0) { ExactDiv(D[P(i)], D[P(i)], t2); for (j = i+1; j <= m; j++) { ExactDiv(lam(j)(P(i)), lam(j)(P(i)), t2); } } for (i = k+1; i <= m; i++) { ExactDiv(lam(i)(P(k-1)), lam(i)(P(k-1)), t3); } swap(P(k-1), P(k)); return 1; } else { swap(B(k-1), B(k)); if (U) swap((*U)(k-1), (*U)(k)); for (j = 1; j <= k-2; j++) if (P(j) != 0) swap(lam(k-1)(P(j)), lam(k)(P(j))); swap(P(k-1), P(k)); return 0; } }