From f8ad044f4197e4b5087d54bc7a917eff9fda5979 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:35:10 -0700 Subject: [PATCH 1/6] ConvexSet_base.representative_point: New --- src/sage/geometry/convex_set.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 604df756af0..74eabb91bf6 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -622,6 +622,24 @@ def relative_interior(self): return self raise NotImplementedError + @cached_method + def representative_point(self): + """ + Return a "generic" point of ``self``. + + OUTPUT: + + A point in the relative interior of ``self`` as a coordinate vector. + + EXAMPLES:: + + sage: C = Cone([[1, 2, 0], [2, 1, 0]]) + sage: C.representative_point() + (1, 1, 0) + """ + affine_basis = self.an_affine_basis() + return sum(affine_basis) / len(affine_basis) + def _test_convex_set(self, tester=None, **options): """ Run some tests on the methods of :class:`ConvexSet_base`. From 8ba6fcd652cc84a5d22777f5781f1d02f33b243a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:36:02 -0700 Subject: [PATCH 2/6] Polyhedron_base1.an_affine_basis: Implement for the unbounded pointed case --- src/sage/geometry/cone.py | 14 ++++------- src/sage/geometry/polyhedron/base1.py | 34 +++++++++++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d9d57b3b12a..bbdfe3e3f3b 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -3533,21 +3533,17 @@ def an_affine_basis(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.an_affine_basis() - Traceback (most recent call last): - ... - NotImplementedError: this function is not implemented for unbounded polyhedra + [(0, 0), (1, 0), (0, 1)] sage: ray = Cone([(1, 1)]) sage: ray.an_affine_basis() - Traceback (most recent call last): - ... - NotImplementedError: this function is not implemented for unbounded polyhedra + [(0, 0), (1, 1)] sage: line = Cone([(1,0), (-1,0)]) - sage: line.an_affine_basis() + sage: line.an_affine_basis() # FIXME Traceback (most recent call last): ... - NotImplementedError: this function is not implemented for unbounded polyhedra + NameError: free variable 'vertex' referenced before assignment in enclosing scope """ - return self.polyhedron().an_affine_basis() + return [vector(v) for v in self.polyhedron().an_affine_basis()] @cached_method def strict_quotient(self): diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index e36867647f5..3cf14d9ad88 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -455,16 +455,23 @@ def an_affine_basis(self): A vertex at (4, 1, 3, 5, 2), A vertex at (4, 2, 5, 3, 1)] - The method is not implemented for unbounded polyhedra:: + For unbounded polyhedra, the result may contain arbitrary points of ``self``, + not just vertices:: - sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) + sage: p = Polyhedron(vertices=[(0, 0)], rays=[(1,0), (0,1)]) sage: p.an_affine_basis() + [A vertex at (0, 0), (1, 0), (0, 1)] + sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0), (0,1)]) + sage: p.an_affine_basis() + [A vertex at (2, 1), (3, 1), (2, 2)] + sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0)], lines=[(0,1)]) + sage: p.an_affine_basis() # FIXME Traceback (most recent call last): ... - NotImplementedError: this function is not implemented for unbounded polyhedra + NameError: free variable 'vertex' referenced before assignment in enclosing scope """ - if not self.is_compact(): - raise NotImplementedError("this function is not implemented for unbounded polyhedra") + ## if not self.is_compact(): + ## raise NotImplementedError("this function is not implemented for unbounded polyhedra") chain = self.a_maximal_chain()[1:] # we exclude the empty face chain_indices = [face.ambient_V_indices() for face in chain] @@ -472,25 +479,32 @@ def an_affine_basis(self): # We use in the following that elements in ``chain_indices`` are sorted lists # of V-indices. - # Thus for each two faces we can easily find the first vertex that differs. + # Thus for each two faces we can easily find the first Vrep that differs. for dim, face in enumerate(chain_indices): if dim == 0: - # Append the vertex. + # Append the V-index. basis_indices.append(face[0]) continue prev_face = chain_indices[dim-1] for i in range(len(prev_face)): if prev_face[i] != face[i]: - # We found a vertex that ``face`` has, but its facet does not. + # We found a Vrep that ``face`` has, but its facet does not. basis_indices.append(face[i]) break else: # no break # ``prev_face`` contains all the same vertices as ``face`` until now. - # But ``face`` is guaranteed to contain one more vertex (at least). + # But ``face`` is guaranteed to contain one more Vrep (at least). basis_indices.append(face[len(prev_face)]) - return [self.Vrepresentation()[i] for i in basis_indices] + Vreps = [self.Vrepresentation()[i] for i in basis_indices] + if all(vrep.is_vertex() for vrep in Vreps): + return Vreps + for vrep in Vreps: + if vrep.is_vertex(): + vertex = vrep + return [vrep if vrep.is_vertex() else vertex.vector() + vrep.vector() + for vrep in Vreps] @abstract_method def a_maximal_chain(self): From f0708e787786d25316b623a0f06d6b5b869c523b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:45:45 -0700 Subject: [PATCH 3/6] RelativeInterior.representative_point: New --- src/sage/geometry/relative_interior.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/geometry/relative_interior.py b/src/sage/geometry/relative_interior.py index 8f463170aad..262c927a08a 100644 --- a/src/sage/geometry/relative_interior.py +++ b/src/sage/geometry/relative_interior.py @@ -276,6 +276,22 @@ def _some_elements_(self): if p in self: yield p + def representative_point(self): + """ + Return a "generic" point of ``self``. + + OUTPUT: + + A point in ``self`` (thus, in the relative interior of ``self``) as a coordinate vector. + + EXAMPLES:: + + sage: C = Cone([[1, 2, 0], [2, 1, 0]]) + sage: C.relative_interior().representative_point() + (1, 1, 0) + """ + return self._polyhedron.representative_point() + def _repr_(self): r""" Return a description of ``self``. From 5f3a8ed7d40a6d22beb1212e7ade912856f4d394 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:46:08 -0700 Subject: [PATCH 4/6] ConvexSet_base._some_elements_: Provide a default implementation --- src/sage/geometry/convex_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 74eabb91bf6..695f118311b 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -764,7 +764,6 @@ def some_elements(self): raise NotImplementedError return list(self._some_elements_()) - @abstract_method(optional=True) def _some_elements_(self): r""" Generate some points of ``self``. @@ -775,11 +774,12 @@ def _some_elements_(self): sage: from sage.geometry.convex_set import ConvexSet_base sage: C = ConvexSet_base() - sage: C._some_elements_(C) + sage: list(C._some_elements_()) Traceback (most recent call last): ... TypeError: 'NotImplementedType' object is not callable """ + yield self.representative_point() @abstract_method(optional=True) def cartesian_product(self, other): From bfe56c6c6675444d5c767772220b94649163ca1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 16:02:01 -0700 Subject: [PATCH 5/6] Polyhedron_base1.an_affine_basis: Implement for the non-pointed case --- src/sage/geometry/cone.py | 6 ++---- src/sage/geometry/polyhedron/base1.py | 13 ++++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index bbdfe3e3f3b..09b0f3cd1c3 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -3538,10 +3538,8 @@ def an_affine_basis(self): sage: ray.an_affine_basis() [(0, 0), (1, 1)] sage: line = Cone([(1,0), (-1,0)]) - sage: line.an_affine_basis() # FIXME - Traceback (most recent call last): - ... - NameError: free variable 'vertex' referenced before assignment in enclosing scope + sage: line.an_affine_basis() + [(1, 0), (0, 0)] """ return [vector(v) for v in self.polyhedron().an_affine_basis()] diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 3cf14d9ad88..7a404a5097f 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -465,14 +465,9 @@ def an_affine_basis(self): sage: p.an_affine_basis() [A vertex at (2, 1), (3, 1), (2, 2)] sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0)], lines=[(0,1)]) - sage: p.an_affine_basis() # FIXME - Traceback (most recent call last): - ... - NameError: free variable 'vertex' referenced before assignment in enclosing scope + sage: p.an_affine_basis() + [(2, 1), A vertex at (2, 0), (3, 0)] """ - ## if not self.is_compact(): - ## raise NotImplementedError("this function is not implemented for unbounded polyhedra") - chain = self.a_maximal_chain()[1:] # we exclude the empty face chain_indices = [face.ambient_V_indices() for face in chain] basis_indices = [] @@ -482,8 +477,8 @@ def an_affine_basis(self): # Thus for each two faces we can easily find the first Vrep that differs. for dim, face in enumerate(chain_indices): if dim == 0: - # Append the V-index. - basis_indices.append(face[0]) + # Append the V-indices of the minimal face. + basis_indices.extend(face[:]) continue prev_face = chain_indices[dim-1] From 6522eff7f2d98703a6aa3f7ee72a42d60c6aa63d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 17:45:25 -0700 Subject: [PATCH 6/6] Polyhedron_base1.an_affine_basis: Update documentation --- src/sage/geometry/polyhedron/base1.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 7a404a5097f..42a87ecb173 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -426,7 +426,7 @@ def ambient_dim(self): def an_affine_basis(self): """ - Return points in ``self`` that are a basis for the affine span of the polytope. + Return points in ``self`` that form a basis for the affine span of ``self``. This implementation of the method :meth:`ConvexSet_base.an_affine_basis` for polytopes guarantees the following: @@ -438,6 +438,9 @@ def an_affine_basis(self): one vertex that is in the difference. Thus this method is independent of the concrete realization of the polytope. + For unbounded polyhedra, the result may contain arbitrary points of ``self``, + not just vertices. + EXAMPLES:: sage: P = polytopes.cube() @@ -455,8 +458,7 @@ def an_affine_basis(self): A vertex at (4, 1, 3, 5, 2), A vertex at (4, 2, 5, 3, 1)] - For unbounded polyhedra, the result may contain arbitrary points of ``self``, - not just vertices:: + Unbounded polyhedra:: sage: p = Polyhedron(vertices=[(0, 0)], rays=[(1,0), (0,1)]) sage: p.an_affine_basis()