Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maximal angles between convex cones #37854

Merged
merged 71 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
0ceab7d
Trac #29169: add the Or2020 reference.
orlitzky Feb 9, 2020
5577cd1
Trac #29169: add the geometry/cone_critical_angles module.
orlitzky Feb 9, 2020
df5c5b6
Trac #29169: add the critical_angles and max_angle methods.
orlitzky Feb 9, 2020
0f782c1
Trac #29169: tweak two max/critical angle error messages.
orlitzky Sep 18, 2020
f7ff1b7
Trac #29169: improve error message for _random_admissible_cone().
orlitzky Sep 18, 2020
f83a6d4
Trac #29169: remove two unused example lines.
orlitzky Sep 18, 2020
9ae23ac
Trac #29169: take advantage of improvements in trac #30605.
orlitzky Sep 19, 2020
6a44206
Trac #29169: remove set_random_seed() calls.
orlitzky Dec 2, 2021
fb832ad
Trac #29169: fix a few typos.
orlitzky Mar 6, 2022
d0867f4
Trac #29169: convert solve_gevp* functions to generators.
orlitzky Mar 6, 2022
406599f
Trac #29169: add a warning about inexact critical angle arithmetic.
orlitzky Mar 6, 2022
e416d85
Trac #29169: add an exact=False example for cone max_angle().
orlitzky Mar 6, 2022
e88ad09
Trac #29169: clean up two import lists in cone_critical_angles.py.
orlitzky Mar 7, 2022
7f032ae
Trac #29169: use matroid implementation for gevp_licis().
orlitzky Mar 7, 2022
a785b88
Trac #29169: switch from QQbar to AA for cone critical angles.
orlitzky Mar 7, 2022
0acb3d3
Trac #29169: use base ring's zero for the zero-eigenvalue subproblem.
orlitzky Mar 9, 2022
3fea1b6
Trac #29169: return immutable vectors from eigenvalue problems.
orlitzky Mar 9, 2022
f0e39cc
Trac #29169: replace _lists_equivalent() with set equality.
orlitzky Mar 9, 2022
9d0e3e6
Trac #29169: kill periods at the end of INPUT/OUTPUT list items.
orlitzky Mar 10, 2022
d0e24ed
Trac #29169: kill spaces around [ list comprehensions ].
orlitzky Mar 10, 2022
8347ba5
Trac #29169: change "irrelevant" to "ignored" in a docstring.
orlitzky Mar 10, 2022
a81dfbd
src/doc/en/reference/references/index.rst: add the Or2024 reference
orlitzky Apr 22, 2024
861b00e
src/sage/geometry/cone.py: consolidate "long time"
orlitzky Apr 22, 2024
893029a
src/sage/geometry/cone_critical_angles.py: consolidate "long time"
orlitzky Apr 22, 2024
82caf7e
src/sage/geometry/cone_critical_angles.py: max angle continuity fallback
orlitzky Apr 23, 2024
1cdbabe
src/sage/geometry/cone_critical_angles.py: fix critical_angles comment
orlitzky Apr 23, 2024
d3d6f5d
src/sage/geometry/cone*.py: drop critical_angles() method
orlitzky Apr 23, 2024
be692ea
src/sage/geometry/cone.py: document the inexact fallback for max_angle()
orlitzky Apr 23, 2024
37d3cd4
src/sage/geometry/cone*.py: fix pycodestyle warnings
orlitzky Apr 23, 2024
7049f90
src/sage/geometry/cone_critical_angles.py: don't import from "all"
orlitzky Apr 23, 2024
e489fae
src/sage/geometry/cone_critical_angles.py: drop unused _is_critical()
orlitzky Apr 24, 2024
909f42c
src/sage/geometry/cone_critical_angles.py: rewrap long lines
orlitzky Apr 24, 2024
ca7b571
src/sage/geometry/cone.py: rewrap long lines
orlitzky Apr 24, 2024
a53e706
src/sage/geometry/cone.py: allow the full space in max_angle()
orlitzky Apr 24, 2024
d5778f4
src/sage/geometry/cone_critical_angles.py: the full space is admissible
orlitzky Apr 24, 2024
6db77f6
src/sage/geometry/cone.py: update a max_angle() test
orlitzky Apr 24, 2024
828d328
src/sage/geometry/cone.py: test the full space in max_angle()
orlitzky Apr 24, 2024
89c9d91
src/sage/geometry/cone*.py: max_angle() documentation improvements
orlitzky Apr 24, 2024
d158da3
src/sage/geometry/cone.py: one max_angle() test case is still crashy
orlitzky Apr 24, 2024
03c9230
src/sage/geometry/cone.py: bring back the max_angle() warning
orlitzky Apr 24, 2024
fb8ea6c
src/sage/geometry/cone_critical_angles.py: minor doc rendering issues
orlitzky Apr 24, 2024
e7cd5df
src/sage/geometry/cone.py: both -> each, in a docstring
orlitzky Apr 24, 2024
c5725fc
src/sage/geometry/cone_critical_angles.py: delete "." in the module t…
orlitzky Apr 24, 2024
e9f2172
src/sage/geometry/cone_critical_angles.py: no "-" in linearly indepen…
orlitzky Apr 25, 2024
dccc60c
src/sage/geometry/cone_critical_angles.py: align matrix blocks
orlitzky Apr 25, 2024
8a18017
src/sage/geometry/cone_critical_angles.py: consistent doctest indenta…
orlitzky Apr 25, 2024
4956d2c
src/sage/geometry/cone_critical_angles.py: capitalize Gram
orlitzky Apr 25, 2024
000045f
src/sage/geometry/cone_critical_angles.py: reindent two doctests
orlitzky Apr 25, 2024
f43c251
src/sage/geometry/cone_critical_angles.py: avoid superscript "th" in …
orlitzky Apr 25, 2024
3b042e7
src/sage/geometry/cone.py: don't define P,Q in max_angle()
orlitzky May 3, 2024
ac302c3
src/sage/geometry/cone.py: "your cones" -> "the cones" in max_angle()…
orlitzky May 3, 2024
33bb8a4
src/sage/geometry/cone.py: add "noted in" before a citation
orlitzky May 3, 2024
603341a
src/sage/geometry/cone.py: reindent the WARNING block in max_angle()
orlitzky May 3, 2024
677bde3
src/sage/geometry/cone.py: don't put \text around "max" subscript
orlitzky May 3, 2024
e4d9749
src/sage/geometry/cone_critical_angles.py: add another SS2016 citation
orlitzky May 3, 2024
10d33a9
src/sage/geometry/cone_critical_angles.py: misc PEP8 corrections
orlitzky May 3, 2024
6a8db73
src/sage/geometry/cone_critical_angles.py: another PEP8 fix
orlitzky May 3, 2024
b111700
src/sage/geometry/cone_critical_angles.py: prefer ZZ.zero() to ZZ(0)
orlitzky May 3, 2024
ad1c7b4
src/sage/geometry/cone_critical_angles.py: add more Or2020 citations
orlitzky May 3, 2024
3773c6e
src/sage/geometry/cone_critical_angles.py: change one "don't" to "do …
orlitzky May 3, 2024
1fa06c5
src/sage/geometry/cone.py: fix {max} -> {\max} in subscripts
orlitzky May 4, 2024
cc81025
src/sage/geometry/cone_critical_angles.py: add spaces to solve_gevp* …
orlitzky May 4, 2024
99295e8
src/sage/geometry/cone_critical_angles.py: add spacing to a "filter" …
orlitzky May 4, 2024
f3aa994
src/sage/geometry/cone_critical_angles.py: no extra spaces in block m…
orlitzky May 4, 2024
61cb012
src/sage/geometry/cone_critical_angles.py: micro-optimize solve_gevp_…
orlitzky May 4, 2024
1e742e9
src/sage/geometry/cone_critical_angles.py: use matrix_from_columns()
orlitzky May 4, 2024
32e543a
src/sage/geometry/cone_critical_angles.py: optimize M[I,J] indexing
orlitzky May 4, 2024
dff5441
src/sage/geometry/cone_critical_angles.py: more spaces around *
orlitzky May 4, 2024
ad7c29c
src/sage/geometry/cone_critical_angles.py: avoid indexing in a loop
orlitzky May 6, 2024
30464f7
src/sage/geometry/cone_critical_angles.py: add another "internal" war…
orlitzky May 6, 2024
1b8f08f
src/doc/en/reference/discrete_geometry/index.rst: add cone critical a…
orlitzky May 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/en/reference/discrete_geometry/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Toric geometry
sage/geometry/toric_lattice
sage/geometry/cone
sage/geometry/cone_catalog
sage/geometry/cone_critical_angles
sage/geometry/fan
sage/geometry/fan_morphism
sage/geometry/point_collection
Expand Down
7 changes: 7 additions & 0 deletions src/doc/en/reference/references/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5120,6 +5120,13 @@ REFERENCES:
Electronic Journal of Linear Algebra, 34:444-458, 2018,
:doi:`10.13001/1081-3810.3782`.

.. [Or2020] \M. Orlitzky. When a maximal angle among cones is nonobtuse.
Computational and Applied Mathematics 39(2), 2020.
:doi:`10.1007/s40314-020-1115-y`.

.. [Or2024] \M. Orlitzky. Continuity of the conic hull.
Journal of Convex Analysis 31(1):255-264, 2024.

.. [ORS2013] Peter Ozsvath, Jacob Rasmussen, Zoltan Szabo,
*Odd Khovanov homology*,
Algebraic & Geometric Topology 13 (2013) 1465–1488,
Expand Down
195 changes: 195 additions & 0 deletions src/sage/geometry/cone.py
Original file line number Diff line number Diff line change
Expand Up @@ -6197,6 +6197,201 @@ def Z_operators_gens(self):
"""
return [ -cp for cp in self.cross_positive_operators_gens() ]

def max_angle(self, other=None, exact=True, epsilon=0):
r"""
Return the maximal angle between ``self`` and ``other``.

The maximal angle between two closed convex cones is the
unique largest angle formed by any two unit-norm vectors in
those cones. In pathological cases, this computation can fail.

If it fails when ``exact`` is ``True`` and if each of the
cones :meth:`is_strictly_convex`, then a second attempt will
be made using inexact arithmetic. (This sometimes avoids the
problem noted in [Or2024]_). If the computation fails when the
cones are not strictly convex or when ``exact`` is ``False``,
a :class:`ValueError` is raised.

INPUT:

- ``other`` -- (default: ``None``) a rational, polyhedral
convex cone

- ``exact`` -- (default: ``True``) whether or not to use exact
rational arithmetic instead of floating point computations;
beware that ``True`` is not guaranteed to avoid floating
point computations if the algorithm runs into trouble in
rational arithmetic

- ``epsilon`` -- (default: ``0``) the tolerance to use when
making comparisons

.. WARNING::

Using inexact arithmetic (``exact=False``) is faster, but
this computation is only known to be stable when both of
the cones are strictly convex (or when one of them is the
entire space, but the maximal angle is obviously `\pi` in
that case).

OUTPUT:

A triple `\left( \theta_{\max}, u, v \right)`
containing:

- the maximal angle `\theta_{\max}` between ``self`` and
``other``

- a vector `u` in ``self`` that achieves the maximal angle

- a vector `v` in ``other`` that achieves the maximal angle

If ``other`` is ``None`` (the default), then the maximal angle
within this cone (between this cone and itself) is returned.

If an eigenspace of dimension greater than one is encountered
and if the corresponding angle cannot be ruled out as a
maximum, the behavior of this function depends on
``exact``:

- If ``exact`` is ``True`` and if both ``self`` and ``other``
are strictly convex, then the algorithm will fall back to
inexact arithmetic. In that case, the returned angle and
vectors will be over :class:`sage.rings.real_double.RDF`.

- If ``exact`` is ``False`` or if either cone is not strictly
convex, then a :class:`ValueError` is raised to indicate
that we have failed; i.e. we cannot say with certainty what
the maximal angle is.

REFERENCES:

- [IS2005]_
- [SS2016]_
- [Or2020]_
- [Or2024]_

ALGORITHM:

Algorithm 3 in [Or2020]_ is used. If a potentially-maximal
angle corresponds to an eigenspace of dimension two or more,
we sometimes fall back to inexact arithmetic which has the
effect of perturbing the cones. That this will not affect the
answer too much is one conclusion of [Or2024]_.

EXAMPLES:

The maximal angle in a single ray is zero::

sage: K = random_cone(min_rays=1, max_rays=1, max_ambient_dim=5)
sage: K.max_angle()[0]
0

The maximal angle in the nonnegative octant is `\pi/2`::

sage: K = cones.nonnegative_orthant(3)
sage: K.max_angle()[0]
1/2*pi

The maximal angle between the nonnegative quintant and the
Schur cone of dimension 5 is about `0.8524 \pi`. The same
result can be obtained faster using inexact arithmetic, but
only confidently so because we already know the answer::

sage: # long time
sage: P = cones.nonnegative_orthant(5)
sage: Q = cones.schur(5)
sage: actual = P.max_angle(Q)[0]
sage: expected = 0.8524*pi
sage: bool( (actual - expected).abs() < 0.0001 )
True
sage: actual = P.max_angle(Q,exact=False)[0]
sage: bool( (actual - expected).abs() < 0.0001 )
True

The maximal angle within the Schur cone is known explicitly
via Gourion and Seeger's Proposition 2 [GS2010]_::

sage: n = 3
sage: K = cones.schur(n)
sage: bool(K.max_angle()[0] == ((n-1)/n)*pi)
True

Sage can't prove that the actual and expected results are
equal in the next two cases without a little nudge in the
right direction, and, moreover, it's crashy about it::

sage: n = 4
sage: K = cones.schur(n)
sage: actual = K.max_angle()[0].simplify()._sympy_()._sage_()
sage: expected = ((n-1)/n)*pi
sage: bool( actual == expected )
True
sage: n = 5
sage: K = cones.schur(n)
sage: actual = K.max_angle()[0].simplify()._sympy_()._sage_()
sage: expected = ((n-1)/n)*pi
sage: bool( actual == expected )
True

When there's a unit norm vector in ``self`` whose negation is
in ``other``, they form a maximal angle of `\pi`::

sage: P = Cone([(5,1), (1,-1)])
sage: Q = Cone([(-1,0), (-1,0)])
sage: P.max_angle(Q)[0]
pi

TESTS:

When ``self`` and ``-other`` have nontrivial intersection, we
expect the maximal angle to be `\pi`::

sage: # long time
sage: from sage.geometry.cone_critical_angles import (
....: _random_admissible_cone )
sage: n = ZZ.random_element(1,3)
sage: P = _random_admissible_cone(ambient_dim=n)
sage: Q = _random_admissible_cone(ambient_dim=n)
sage: expected = P.intersection(-Q).is_trivial()
sage: actual = bool(P.max_angle(Q)[0] != pi)
sage: actual == expected
True

In particular, this should happen when either cone is the full
space::

sage: from sage.geometry.cone_critical_angles import (
....: _random_admissible_cone )
sage: n = ZZ.random_element(1,5)
sage: P = _random_admissible_cone(ambient_dim=n)
sage: Q = cones.trivial(n, P.dual().lattice()).dual()
sage: Q.is_full_space()
True
sage: P.max_angle(Q)[0]
pi
sage: Q.max_angle(P)[0]
pi
"""
# We do the argument checking here, in the public cone method,
# because the error message should say something like "this
# cone" and not reference the argument of a function the user
# has never heard of in some internal module.
if self.is_trivial():
raise ValueError("cone should not be trivial")

if other is None:
other = self
else:
if (other.lattice_dim() != self.lattice_dim()):
raise ValueError("lattice dimensions of self and other "
"must agree")
if other.is_trivial():
raise ValueError("other cone cannot be trivial")

from sage.geometry.cone_critical_angles import max_angle
return max_angle(self, other, exact, epsilon)


def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None,
min_rays=0, max_rays=None, strictly_convex=None, solid=None):
Expand Down
Loading
Loading