diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index c6dc7967e4d..ef9f58b2222 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -443,6 +443,45 @@ def affine_hull(self): TypeError: 'NotImplementedType' object is not callable """ + def an_element(self): + r""" + Return a point of ``self``. + + If ``self`` is empty, an :class:`EmptySetError` will be raised. + + The default implementation delegates to :meth:`some_elements`. + + EXAMPLES:: + + sage: from sage.geometry.convex_set import ConvexSet_compact + sage: class BlueBox(ConvexSet_compact): + ....: def some_elements(self): + ....: yield 'blue' + ....: yield 'cyan' + sage: BlueBox().an_element() + """ + try: + return next(iter(self.some_elements())) + except StopIteration: + raise EmptySetError + + @abstract_method(optional=True) + def some_elements(self): + r""" + Generate some points of ``self``. + + If ``self`` is empty, no points are generated; no exception will be raised. + + TESTS:: + + sage: from sage.geometry.convex_set import ConvexSet_base + sage: C = ConvexSet_base() + sage: C.some_elements(C) + Traceback (most recent call last): + ... + TypeError: 'NotImplementedType' object is not callable + """ + @abstract_method(optional=True) def cartesian_product(self, other): """ diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 82af7e683fc..ac1a12fa2e1 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -3302,6 +3302,35 @@ def representative_point(self): accumulator.set_immutable() return accumulator + def some_elements(self): + r""" + Generate some points of ``self``. + + If ``self`` is empty, no points are generated; no exception will be raised. + + EXAMPLES:: + + sage: P = polytopes.simplex() + sage: list(P.some_elements()) + [(1/4, 1/4, 1/4, 1/4), + (0, 0, 0, 1), + (0, 0, 1/2, 1/2), + (0, 1/2, 1/4, 1/4), + (1/2, 1/4, 1/8, 1/8)] + """ + if self.is_empty(): + return + yield self.representative_point() + vertex_iter = iter(self.vertex_generator()) + try: + p = next(vertex_iter).vector() + yield vector(p, immutable=True) + for i in range(4): + p = (p + next(vertex_iter).vector()) / 2 + yield vector(p, immutable=True) + except StopIteration: + pass + def a_maximal_chain(self): r""" Return a maximal chain of the face lattice in increasing order. diff --git a/src/sage/geometry/relative_interior.py b/src/sage/geometry/relative_interior.py index c714faabcb9..b617ff39697 100644 --- a/src/sage/geometry/relative_interior.py +++ b/src/sage/geometry/relative_interior.py @@ -227,6 +227,22 @@ def is_closed(self): assert not self._polyhedron.is_relatively_open() return False + def some_elements(self): + r""" + Generate some points of ``self``. + + If ``self`` is empty, no points are generated; no exception will be raised. + + EXAMPLES:: + + sage: P = polytopes.simplex() + sage: list(P.relative_interior().some_elements()) + [(1/4, 1/4, 1/4, 1/4), (1/2, 1/4, 1/8, 1/8)] + """ + for p in self._polyhedron.some_elements(): + if p in self: + yield p + def _repr_(self): r""" Return a description of ``self``.