def has_rational_point(self, point = False, obstruction = False, algorithm = 'default', read_cache = True): r""" Returns True if and only if ``self`` has a point defined over `\QQ`. If ``point`` and ``obstruction`` are both False (default), then the output is a boolean ``out`` saying whether ``self`` has a rational point. If ``point`` or ``obstruction`` is True, then the output is a pair ``(out, S)``, where ``out`` is as above and the following holds: - if ``point`` is True and ``self`` has a rational point, then ``S`` is a rational point, - if ``obstruction`` is True and ``self`` has no rational point, then ``S`` is a prime such that no rational point exists over the completion at ``S`` or `-1` if no point exists over `\RR`. Points and obstructions are cached, whenever they are found. Cached information is used if and only if ``read_cache`` is True. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: - ``'qfsolve'`` -- Use PARI/GP function ``qfsolve`` - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm (cannot be combined with ``obstruction = True``) - ``'local'`` -- Check if a local solution exists for all primes and infinite places of `\QQ` and apply the Hasse principle (cannot be combined with ``point = True``) - ``'default'`` -- Use ``'qfsolve'`` - ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES:: sage: C = Conic(QQ, [1, 2, -3]) sage: C.has_rational_point(point = True) (True, (1 : 1 : 1)) sage: D = Conic(QQ, [1, 3, -5]) sage: D.has_rational_point(point = True) (False, 3) sage: P.<X,Y,Z> = QQ[] sage: E = Curve(X^2 + Y^2 + Z^2); E Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2 sage: E.has_rational_point(obstruction = True) (False, -1) The following would not terminate quickly with ``algorithm = 'rnfisnorm'`` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) sage: C.has_rational_point(point = True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) sage: C.has_rational_point(algorithm = 'local', read_cache = False) True sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma (True, (30106379962113/7913 : 12747947692/7913 : 1)) TESTS: Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors and returns consistent answers for all algorithms. Check if all points returned are valid. :: sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)])) sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)] sage: d = [] sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = (algorithm != 'rnfisnorm'), point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve', 'rnfisnorm']] for C in c[::10]] # long time: 7 seconds sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d]) sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]]) """ if read_cache: if self._rational_point is not None: if point or obstruction: return True, self._rational_point else: return True if self._local_obstruction is not None: if point or obstruction: return False, self._local_obstruction else: return False if (not point) and self._finite_obstructions == [] and \ self._infinite_obstructions == []: if obstruction: return True, None return True if self.has_singular_point(): if point: return self.has_singular_point(point = True) if obstruction: return True, None return True if algorithm == 'default' or algorithm == 'qfsolve': M = self.symmetric_matrix() M *= lcm([ t.denominator() for t in M.list() ]) pt = qfsolve(M) if pt in ZZ: if self._local_obstruction is None: self._local_obstruction = pt if point or obstruction: return False, pt return False pt = self.point([pt[0], pt[1], pt[2]]) if point or obstruction: return True, pt return True ret = ProjectiveConic_number_field.has_rational_point( \ self, point = point, \ obstruction = obstruction, \ algorithm = algorithm, \ read_cache = read_cache) if point or obstruction: if is_RingHomomorphism(ret[1]): ret[1] = -1 return ret
def has_rational_point(self, point=False, obstruction=False, algorithm='default', read_cache=True): r""" Returns True if and only if ``self`` has a point defined over `\QQ`. If ``point`` and ``obstruction`` are both False (default), then the output is a boolean ``out`` saying whether ``self`` has a rational point. If ``point`` or ``obstruction`` is True, then the output is a pair ``(out, S)``, where ``out`` is as above and the following holds: - if ``point`` is True and ``self`` has a rational point, then ``S`` is a rational point, - if ``obstruction`` is True and ``self`` has no rational point, then ``S`` is a prime such that no rational point exists over the completion at ``S`` or `-1` if no point exists over `\RR`. Points and obstructions are cached, whenever they are found. Cached information is used if and only if ``read_cache`` is True. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: - ``'qfsolve'`` -- Use PARI/GP function ``qfsolve`` - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm (cannot be combined with ``obstruction = True``) - ``'local'`` -- Check if a local solution exists for all primes and infinite places of `\QQ` and apply the Hasse principle (cannot be combined with ``point = True``) - ``'default'`` -- Use ``'qfsolve'`` - ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES:: sage: C = Conic(QQ, [1, 2, -3]) sage: C.has_rational_point(point = True) (True, (1 : 1 : 1)) sage: D = Conic(QQ, [1, 3, -5]) sage: D.has_rational_point(point = True) (False, 3) sage: P.<X,Y,Z> = QQ[] sage: E = Curve(X^2 + Y^2 + Z^2); E Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2 sage: E.has_rational_point(obstruction = True) (False, -1) The following would not terminate quickly with ``algorithm = 'rnfisnorm'`` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) sage: C.has_rational_point(point = True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) sage: C.has_rational_point(algorithm = 'local', read_cache = False) True sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma (True, (30106379962113/7913 : 12747947692/7913 : 1)) TESTS: Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors and returns consistent answers for all algorithms. Check if all points returned are valid. :: sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)])) sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)] sage: d = [] sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = (algorithm != 'rnfisnorm'), point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve', 'rnfisnorm']] for C in c[::10]] # long time: 7 seconds sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d]) sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]]) """ if read_cache: if self._rational_point is not None: if point or obstruction: return True, self._rational_point else: return True if self._local_obstruction is not None: if point or obstruction: return False, self._local_obstruction else: return False if (not point) and self._finite_obstructions == [] and \ self._infinite_obstructions == []: if obstruction: return True, None return True if self.has_singular_point(): if point: return self.has_singular_point(point=True) if obstruction: return True, None return True if algorithm == 'default' or algorithm == 'qfsolve': M = self.symmetric_matrix() M *= lcm([t.denominator() for t in M.list()]) pt = qfsolve(M) if pt in ZZ: if self._local_obstruction is None: self._local_obstruction = pt if point or obstruction: return False, pt return False pt = self.point([pt[0], pt[1], pt[2]]) if point or obstruction: return True, pt return True ret = ProjectiveConic_number_field.has_rational_point( \ self, point = point, \ obstruction = obstruction, \ algorithm = algorithm, \ read_cache = read_cache) if point or obstruction: if is_RingHomomorphism(ret[1]): ret[1] = -1 return ret