Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit 948d992

Browse files
author
Jonathan Kliem
committed
error message for non-spanning gale transform; improved documentation
1 parent 0691033 commit 948d992

File tree

1 file changed

+51
-18
lines changed

1 file changed

+51
-18
lines changed

src/sage/geometry/polyhedron/library.py

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,31 @@ def gale_transform_to_polytope(vectors, base_ring=None, backend=None):
278278
'cdd'
279279
280280
A gale transform corresponds to a polytope if and only if
281-
every (linear) hyperplane not containing any vector
281+
every oriented (linear) hyperplane
282282
has at least two vectors on each side.
283+
See Theorem 6.19 of [Zie2007]_.
284+
If this is not the case, one of two errors is raised.
283285
284-
If this is not the case, an error is raised::
286+
If there is such a hyperplane with no vector on one side,
287+
the vectors are not totally cyclic::
285288
286-
sage: gale_transform_to_polytope([(0,1), (1,1), (1,0), (-1,-1)])
289+
sage: gale_transform_to_polytope([(0,1), (1,1), (1,0), (-1,0)])
287290
Traceback (most recent call last):
288291
...
289-
ValueError: the gale transform does not correspond to a polytope
292+
ValueError: input vectors not totally cyclic
290293
291-
sage: gale_transform_to_polytope([(0,1), (1,1), (1,0), (-1,0)])
294+
If every hyperplane has at least one vector on each side, then the gale
295+
transform corresponds to a point configuration.
296+
It corresponds to a polytope if and only if this point configuration is
297+
convex if and only if every hyperplane contains at least two vectors of
298+
the gale transform on each side.
299+
300+
If this is not the case, an error is raised::
301+
302+
sage: gale_transform_to_polytope([(0,1), (1,1), (1,0), (-1,-1)])
292303
Traceback (most recent call last):
293304
...
294-
ValueError: input vectors not totally cyclic
305+
ValueError: the gale transform does not correspond to a polytope
295306
296307
TESTS::
297308
@@ -309,8 +320,16 @@ def gale_transform_to_polytope(vectors, base_ring=None, backend=None):
309320
"""
310321
vertices = gale_transform_to_primal(vectors, base_ring, backend)
311322
P = Polyhedron(vertices=vertices, base_ring=base_ring, backend=backend)
323+
312324
if not P.n_vertices() == len(vertices):
325+
# If the input vectors are not totally cyclic, ``gale_transform_to_primal``
326+
# raises an error.
327+
# As no error was raised so far, the gale transform corresponds to
328+
# to a point configuration.
329+
# It corresponds to a polytope if and only if
330+
# ``vertices`` are in convex position.
313331
raise ValueError("the gale transform does not correspond to a polytope")
332+
314333
return P
315334

316335
def gale_transform_to_primal(vectors, base_ring=None, backend=None):
@@ -346,22 +365,23 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None):
346365
347366
ALGORITHM:
348367
349-
We assume the centroid of the (input) vectors to be the origin.
350-
We stack ``Matrix(vectors)`` by a row of ones.
351-
The right kernel of this is the dual point configuration.
368+
Step 1: If the centroid of the (input) vectors is not the origin,
369+
we do an appropriate transformation to make it so.
352370
353-
More concretely, the dual vector configuration is obtained by
354-
taking a basis of the right kernel of ``Matrix(vectors)``.
371+
Step 2: We add a row of ones on top of ``Matrix(vectors)``.
372+
The right kernel of this larger matrix is the dual configuration space,
373+
and a basis of this space provides the dual point configuration.
355374
375+
More concretely, the dual vector configuration (inhomogeneous)
376+
is obtained by taking a basis of the right kernel of ``Matrix(vectors)``.
356377
If the centroid of the (input) vectors is the origin,
357-
we can extend the all-ones vector to a basis of the right kernel.
358-
In this case the dual vector configuration can be taken to be
359-
the columns of ``[[1], [V]]``, where ``[1]`` represents
360-
a row of all-ones. Clearly, ``V`` is a dehomogenization.
378+
there exists a basis of the right kernel of the form
379+
``[[1], [V]]``, where ``[1]`` represents a row of ones.
380+
Then, ``V`` is a dehomogenization and thus the dual point configuration.
361381
362-
Extending the all-ones vector to a basis of the right kernel is
363-
done by stacking a row of ones on ``Matrix(vectors)`` and then
364-
taking the right kernel.
382+
To extend ``[1]`` to a basis of ``Matrix(vectors)``, we add
383+
a row of ones to ``Matrix(vectors)`` and calculate a basis of the
384+
right kernel of the obtained matrix.
365385
366386
REFERENCES:
367387
@@ -426,6 +446,13 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None):
426446
Traceback (most recent call last):
427447
...
428448
ValueError: input vectors not totally cyclic
449+
450+
sage: gale_transform_to_primal(
451+
....: [(1,1,0), (-1,-1,0), (1,0,0),
452+
....: (-1,0,0), (1,-1,0), (-2,1,0)], backend='field')
453+
Traceback (most recent call last):
454+
...
455+
ValueError: input vectors not totally cyclic
429456
"""
430457
from sage.modules.free_module_element import vector
431458
from sage.matrix.all import Matrix
@@ -473,6 +500,12 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None):
473500
m = Matrix(base_ring, vectors).transpose().stack(Matrix(base_ring, [[1]*len(vectors)]))
474501
else:
475502
m = Matrix(vectors).transpose().stack(Matrix([[1]*len(vectors)]))
503+
504+
if m.rank() != len(vectors[0]) + 1:
505+
# The given vectors do not span the ambient space,
506+
# then there exists a nonnegative value vector.
507+
raise ValueError("input vectors not totally cyclic")
508+
476509
return m.right_kernel_matrix(basis='computed').columns()
477510

478511

0 commit comments

Comments
 (0)