def det_given_divisor(A, d, proof=True, stabilize=2): """ Given a divisor d of the determinant of A, compute the determinant of A. INPUT: - ``A`` -- a square integer matrix - ``d`` -- a nonzero integer that is assumed to divide the determinant of A - ``proof`` -- bool (default: True) compute det modulo enough primes so that the determinant is computed provably correctly (via the Hadamard bound). It would be VERY hard for ``det()`` to fail even with proof=False. - ``stabilize`` -- int (default: 2) if proof = False, then compute the determinant modulo `p` until ``stabilize`` successive modulo determinant computations stabilize. OUTPUT: integer -- determinant EXAMPLES:: sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf sage: a = matrix(ZZ,3,[-1, -1, -1, -20, 4, 1, -1, 1, 2]) sage: matrix_integer_dense_hnf.det_given_divisor(a, 3) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False, stabilize=1) -30 sage: a.det() -30 Here we illustrate proof=False giving a wrong answer:: sage: p = matrix_integer_dense_hnf.max_det_prime(2) sage: q = previous_prime(p) sage: a = matrix(ZZ, 2, [p, 0, 0, q]) sage: p * q 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=2) 0 This still works, because we don't work modulo primes that divide the determinant bound, which is found using a p-adic algorithm:: sage: a.det(proof=False, stabilize=2) 70368442188091 3 primes is enough:: sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=3) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=5) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=True) 70368442188091 TESTS:: sage: m = diagonal_matrix(ZZ, 68, [2]*66 + [1,1]) sage: m.det() 73786976294838206464 """ p = max_det_prime(A.nrows()) z_mod = [] moduli = [] assert d != 0 z_so_far = 1 N_so_far = 1 if proof: N = 1 B = (2 * 10**A.hadamard_bound()) // d + 1 dd = d # bad verbose statement, since computing the log overflows! est = int(RR(B).log() / RR(p).log()) + 1 cnt = 1 verbose("Multimodular det -- need to use about %s primes."%est, level=1) while N < B: if d % p != 0: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor(A, d, p, z_mod, moduli, z_so_far, N_so_far) N *= p verbose("computed det mod p=%s which is %s (of about %s)"%(p, cnt, est), tm) p = previous_prime(p) cnt += 1 return dd else: val = [] while True: if d % p != 0: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor(A, d, p, z_mod, moduli, z_so_far, N_so_far) verbose("computed det mod %s"%p, tm) val.append(dd) if len(val) >= stabilize and len(set(val[-stabilize:])) == 1: return val[-1] p = previous_prime(p)
def det_given_divisor(A, d, proof=True, stabilize=2): """ Given a divisor d of the determinant of A, compute the determinant of A. INPUT:: - ``A`` -- a square integer matrix - ``d`` -- a nonzero integer that is assumed to divide the determinant of A - ``proof`` -- bool (default: True) compute det modulo enough primes so that the determinant is computed provably correctly (via the Hadamard bound). It would be VERY hard for ``det()`` to fail even with proof=False. - ``stabilize`` -- int (default: 2) if proof = False, then compute the determinant modulo `p` until ``stabilize`` successive modulo determinant computations stabilize. OUTPUT: integer -- determinant EXAMPLES:: sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf sage: a = matrix(ZZ,3,[-1, -1, -1, -20, 4, 1, -1, 1, 2]) sage: matrix_integer_dense_hnf.det_given_divisor(a, 3) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False, stabilize=1) -30 sage: a.det() -30 Here we illustrate proof=False giving a wrong answer:: sage: p = matrix_integer_dense_hnf.max_det_prime(2) sage: q = previous_prime(p) sage: a = matrix(ZZ, 2, [p, 0, 0, q]) sage: p * q 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=2) 0 This still works, because we don't work modulo primes that divide the determinant bound, which is found using a p-adic algorithm:: sage: a.det(proof=False, stabilize=2) 70368442188091 3 primes is enough:: sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=3) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=5) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=True) 70368442188091 TESTS:: sage: m = diagonal_matrix(ZZ, 68, [2]*66 + [1,1]) sage: m.det() 73786976294838206464 """ p = max_det_prime(A.nrows()) z_mod = [] moduli = [] assert d != 0 z_so_far = 1 N_so_far = 1 if proof: N = 1 B = (2 * 10**A.hadamard_bound()) // d + 1 dd = d # bad verbose statement, since computing the log overflows! est = int(RR(B).log() / RR(p).log()) + 1 cnt = 1 verbose("Multimodular det -- need to use about %s primes." % est, level=1) while N < B: if d % p != 0: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor( A, d, p, z_mod, moduli, z_so_far, N_so_far) N *= p verbose( "computed det mod p=%s which is %s (of about %s)" % (p, cnt, est), tm) p = previous_prime(p) cnt += 1 return dd else: val = [] while True: if d % p != 0: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor( A, d, p, z_mod, moduli, z_so_far, N_so_far) verbose("computed det mod %s" % p, tm) val.append(dd) if len(val) >= stabilize and len(set(val[-stabilize:])) == 1: return val[-1] p = previous_prime(p)