Skip to content

Commit

Permalink
Trac #30605: improve cone containment tests
Browse files Browse the repository at this point in the history
If `K` is a polyhedral cone, the test `x in K` only supports `x` with
rational coordinates. It is desirable in many cases to perform the same
test with irrational numbers as well.

This will simplify the implementation in ticket #29169.

URL: https://trac.sagemath.org/30605
Reported by: mjo
Ticket author(s): Michael Orlitzky
Reviewer(s): Jonathan Kliem
  • Loading branch information
Release Manager committed Sep 27, 2020
2 parents ad0f8e0 + 7ea2dd8 commit ed7c4a3
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 39 deletions.
6 changes: 3 additions & 3 deletions build/pkgs/configure/checksums.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tarball=configure-VERSION.tar.gz
sha1=384646584233b2b43d67518772f298064ef46887
md5=82a3a0b22d5bb54dde5eba74356e5c73
cksum=462963871
sha1=0844b6fc043ed89d8cc0d1ffd32ab38d3e2d355a
md5=22f22483c1da51c1cef22833e3ec82ea
cksum=1843480734
2 changes: 1 addition & 1 deletion build/pkgs/configure/package-version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7be0559bbb823f318412c21e720bf91710ffac12
e90b2d71aab2289a07c3e04c41fd536001faa1d2
141 changes: 106 additions & 35 deletions src/sage/geometry/cone.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
from sage.matrix.all import column_matrix, matrix, MatrixSpace
from sage.misc.all import cached_method, flatten, latex
from sage.modules.all import span, vector, VectorSpace
from sage.rings.all import QQ, RR, ZZ
from sage.rings.all import QQ, ZZ
from sage.structure.all import SageObject, parent
from sage.structure.richcmp import richcmp_method, richcmp
from ppl import (C_Polyhedron, Generator_System, Constraint_System,
Expand Down Expand Up @@ -526,47 +526,85 @@ def _ambient_space_point(body, data):
OUTPUT:
- integral, rational or numeric point of the ambient space of ``body``
if ``data`` were successfully interpreted in such a way, otherwise a
``TypeError`` exception is raised
An integral, rational, real algebraic, or numeric point of the
ambient space of ``body`` is returned if ``data`` were
successfully interpreted in such a way. A ``TypeError`` is raised
otherwise.
TESTS::
sage: from sage.geometry.cone import _ambient_space_point
sage: c = Cone([(1,0), (0,1)])
sage: _ambient_space_point(c, [1,1])
N(1, 1)
sage: _ambient_space_point(c, vector(ZZ,[1,1]))
N(1, 1)
sage: _ambient_space_point(c, c.dual_lattice()([1,1]))
Traceback (most recent call last):
...
TypeError: the point M(1, 1) and
2-d cone in 2-d lattice N have incompatible lattices
sage: _ambient_space_point(c, [1,1/3])
(1, 1/3)
sage: _ambient_space_point(c, vector(QQ,[1,1/3]))
(1, 1/3)
sage: _ambient_space_point(c, [1/2,1/sqrt(3)])
(0.500000000000000, 0.577350269189626)
(1/2, 0.5773502691896258?)
sage: _ambient_space_point(c, vector(AA,[1/2,1/sqrt(3)]))
(1/2, 0.5773502691896258?)
sage: _ambient_space_point(c, [1,1,3])
Traceback (most recent call last):
...
TypeError: [1, 1, 3] does not represent a valid point
in the ambient space of 2-d cone in 2-d lattice N
in the ambient space of 2-d cone in 2-d lattice N
sage: _ambient_space_point(c, vector(ZZ,[1,1,3]))
Traceback (most recent call last):
...
TypeError: (1, 1, 3) does not represent a valid point
in the ambient space of 2-d cone in 2-d lattice N
Ensure that transcendental elements can, at the very least, be
represented numerically::
sage: from sage.geometry.cone import _ambient_space_point
sage: c = Cone([(1,0), (0,1)])
sage: _ambient_space_point(c, [1, pi])
(1.00000000000000, 3.14159265358979)
sage: _ambient_space_point(c, vector(SR,[1, pi]))
(1.00000000000000, 3.14159265358979)
"""
from sage.rings.all import AA, RR

L = body.lattice()
try: # to make a lattice element...
return L(data)
except TypeError:
# Special treatment for toric lattice elements
if is_ToricLattice(parent(data)):
raise TypeError("the point %s and %s have incompatible "
"lattices" % (data, body))
try: # ... or an exact point...
return L.base_extend(QQ)(data)
except TypeError:
pass
try: # ... or at least a numeric one
return L.base_extend(RR)(data)
except TypeError:
pass

def try_base_extend(ring):
# Factor out the "try this ring..." code that's repeated four
# times.
try:
return L.base_extend(ring)(data)
except TypeError:
pass
except ValueError as ex:
if str(ex).startswith("Cannot coerce"):
pass

# Special treatment for toric lattice elements
p = try_base_extend(ZZ)
if p is not None:
return p
if is_ToricLattice(parent(data)):
raise TypeError("the point %s and %s have incompatible "
"lattices" % (data, body))

# If we don't have a lattice element, try successively
# less-desirable ambient spaces until (as a last resort) we
# attempt a numerical representation.
for ring in [QQ, AA, RR]:
p = try_base_extend(ring)
if p is not None:
return p

# Raise TypeError with our own message
raise TypeError("%s does not represent a valid point in the ambient "
"space of %s" % (data, body))
Expand Down Expand Up @@ -1546,34 +1584,67 @@ def _contains(self, point, region='whole cone'):
This function is called by :meth:`__contains__` and :meth:`contains`
to ensure the same call depth for warning messages.
By default, a point on the boundary of the cone is considered
part of the cone. If you want to test whether the
**interior** of the cone contains the point, you need to pass
the optional argument ``'interior'``. If you want to test
whether the **relative interior** of the cone contains the
point, you need to pass the optional argument
``'relative_interior'``.
.. WARNING::
The boundary of a closed convex cone is determined by a
set of inequalities. If your ``point`` has entries in an
inexact ring, it will sometimes be impossible to say (with
confidence) if that point lies on the boundary of the cone
or slightly inside it.
INPUT:
- ``point`` -- anything. An attempt will be made to convert it into a
single element of the ambient space of ``self``. If it fails,
``False`` is returned;
- ``point`` -- anything; an attempt will be made to convert it
into an element compatible with the ambient space of ``self``.
- ``region`` -- string. Can be either 'whole cone' (default),
'interior', or 'relative interior'. By default, a point on
the boundary of the cone is considered part of the cone. If
you want to test whether the **interior** of the cone
contains the point, you need to pass the optional argument
``'interior'``. If you want to test whether the **relative
interior** of the cone contains the point, you need to pass
the optional argument ``'relative_interior'``.
- ``region`` -- a string (default: 'whole cone'); can be
either 'whole cone', 'interior', or 'relative interior'.
OUTPUT:
- ``True`` if ``point`` is contained in the specified ``region`` of
``self``, ``False`` otherwise.
``True`` is returned if ``point`` is contained in the
specified ``region`` of ``self``. ``False`` is returned
otherwise, in particular when ``point`` is incompatible with
the ambient space.
Raises a ``ValueError`` if ``region`` is not one of the
A ``ValueError`` is raised if ``region`` is not one of the
three allowed values.
TESTS::
sage: c = Cone([(1,0), (0,1)])
sage: c._contains((1,1))
True
We can test vectors with irrational components::
sage: c = Cone([(1,0), (0,1)])
sage: c._contains((1,sqrt(2)))
True
sage: c._contains(vector(SR, [1,pi]))
True
Ensure that complex vectors are not contained in a real cone::
sage: c = Cone([(1,0), (0,1)])
sage: c._contains((1,I))
False
sage: c._contains(vector(QQbar,[1,I]))
False
And we refuse to coerce elements of another lattice into ours::
sage: c = Cone([(1,0), (0,1)])
sage: c._contains(c.dual().ray(0))
False
"""
try:
point = _ambient_space_point(self, point)
Expand Down

0 comments on commit ed7c4a3

Please sign in to comment.