Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge #31718
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Koeppe committed Apr 26, 2021
2 parents de32db6 + e026e7a commit 5a072cf
Show file tree
Hide file tree
Showing 14 changed files with 562 additions and 81 deletions.
2 changes: 2 additions & 0 deletions src/doc/en/reference/manifolds/manifold.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ Topological Manifolds
sage/manifolds/topological_submanifold

vector_bundle

sage/manifolds/family
18 changes: 17 additions & 1 deletion src/sage/graphs/digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -3317,12 +3317,28 @@ def layout_acyclic_dummy(self, heights=None, rankdir='up', **options):
...
ValueError: `self` should be an acyclic graph
TESTS:
:trac:`31681` is fixed::
sage: H = DiGraph({0: [1], 'X': [1]}, format='dict_of_lists')
sage: pos = H.layout_acyclic_dummy(rankdir='up')
sage: pos['X'][1] == 0 and pos[0][1] == 0
True
sage: pos[1][1] == 1
True
"""
if heights is None:
if not self.is_directed_acyclic():
raise ValueError("`self` should be an acyclic graph")
levels = self.level_sets()
levels = [sorted(z) for z in levels]
# Sort vertices in each level in best effort mode
for i in range(len(levels)):
try:
l = sorted(levels[i])
levels[i] = l
except:
continue
if rankdir=='down' or rankdir=='left':
levels.reverse()
heights = {i: levels[i] for i in range(len(levels))}
Expand Down
8 changes: 3 additions & 5 deletions src/sage/manifolds/differentiable/diff_form_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,14 @@ def _an_element_(self):
"""
resu = self.element_class(self._vmodule, self._degree)
# Non-trivial open covers of the domain:
open_covers = self._domain.open_covers()[1:] # the open cover 0
# is trivial
if open_covers != []:
oc = open_covers[0] # the first non-trivial open cover is selected
for oc in self._domain.open_covers(trivial=False):
# the first non-trivial open cover is selected
for dom in oc:
vmodule_dom = dom.vector_field_module(
dest_map=self._dest_map.restrict(dom))
dmodule_dom = vmodule_dom.dual_exterior_power(self._degree)
resu.set_restriction(dmodule_dom._an_element_())
return resu
return resu

def _coerce_map_from_(self, other):
Expand Down
18 changes: 7 additions & 11 deletions src/sage/manifolds/differentiable/examples/sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,9 @@ class Sphere(PseudoRiemannianSubmanifold):
sage: stereoN, stereoS = S2.coordinate_charts('stereographic')
sage: stereoN, stereoS
(Chart (S^2-{NP}, (y1, y2)), Chart (S^2-{SP}, (yp1, yp2)))
sage: S2.open_covers()
[[2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3],
[Open subset S^2-{NP} of the 2-sphere S^2 of radius 1 smoothly
embedded in the Euclidean space E^3,
Open subset S^2-{SP} of the 2-sphere S^2 of radius 1 smoothly
embedded in the Euclidean space E^3]]
sage: list(S2.open_covers())
[Set {S^2} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,
Set {S^2-{NP}, S^2-{SP}} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3]
.. NOTE::
Expand Down Expand Up @@ -501,11 +498,10 @@ def _init_chart_domains(self):
TESTS::
sage: S2 = manifolds.Sphere(2)
sage: S2.open_covers()
[[2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3],
[Open subset S^2-{NP} of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,
Open subset S^2-{SP} of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3]]
sage: S2.subsets() # random
sage: list(S2.open_covers())
[Set {S^2} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,
Set {S^2-{NP}, S^2-{SP}} of open subsets of the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3]
sage: frozenset(S2.subsets()) # random
frozenset({Euclidean 2-sphere S^2 of radius 1,
Open subset A of the Euclidean 2-sphere S^2 of radius 1,
Open subset S^2-{NP,SP} of the Euclidean 2-sphere S^2 of radius 1,
Expand Down
9 changes: 3 additions & 6 deletions src/sage/manifolds/differentiable/multivector_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,17 +344,14 @@ def _an_element_(self):
"""
resu = self.element_class(self._vmodule, self._degree)
# Non-trivial open covers of the domain:
open_covers = self._domain.open_covers()[1:] # the open cover 0
# is trivial
if open_covers != []:
oc = open_covers[0] # the first non-trivial open cover is
# selected
for oc in self._domain.open_covers(trivial=False):
# the first non-trivial open cover is selected
for dom in oc:
vmodule_dom = dom.vector_field_module(
dest_map=self._dest_map.restrict(dom))
dmodule_dom = vmodule_dom.exterior_power(self._degree)
resu.set_restriction(dmodule_dom._an_element_())
return resu
return resu

def _coerce_map_from_(self, other):
Expand Down
4 changes: 1 addition & 3 deletions src/sage/manifolds/differentiable/tensorfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -2276,9 +2276,7 @@ def __eq__(self, other):
if other._tensor_type != self._tensor_type:
return False
# Non-trivial open covers of the domain:
open_covers = self._domain.open_covers()[1:] # the open cover 0
# is trivial
for oc in open_covers:
for oc in self._domain.open_covers(trivial=False):
resu = True
for dom in oc:
try:
Expand Down
7 changes: 3 additions & 4 deletions src/sage/manifolds/differentiable/tensorfield_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,14 +403,13 @@ def _an_element_(self):
"""
resu = self.element_class(self._vmodule, self._tensor_type)
# Non-trivial open covers of the domain:
open_covers = self._domain.open_covers()[1:] # the open cover 0 is trivial
if open_covers != []:
oc = open_covers[0] # the first non-trivial open cover is selected
for oc in self._domain.open_covers(trivial=False):
# the first non-trivial open cover is selected
for dom in oc:
vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom))
tmodule_dom = vmodule_dom.tensor_module(*(self._tensor_type))
resu.set_restriction(tmodule_dom._an_element_())
return resu
return resu

def _coerce_map_from_(self, other):
Expand Down
8 changes: 3 additions & 5 deletions src/sage/manifolds/differentiable/vectorfield_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,13 @@ def _an_element_(self):
"""
resu = self.element_class(self)
# Non-trivial open covers of the domain:
open_covers = self._domain.open_covers()[1:] # the open cover 0
# is trivial
if open_covers != []:
oc = open_covers[0] # the first non-trivial open cover is selected
for oc in self._domain.open_covers(trivial=False):
# the first non-trivial open cover is selected
for dom in oc:
vmodule_dom = dom.vector_field_module(
dest_map=self._dest_map.restrict(dom))
resu.set_restriction(vmodule_dom._an_element_())
return resu
return resu

def _coerce_map_from_(self, other):
Expand Down
236 changes: 236 additions & 0 deletions src/sage/manifolds/family.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
r"""
Families of Manifold Objects
The class :class:`ManifoldObjectFiniteFamily` is a subclass of :class:`FiniteFamily`
that provides an associative container of manifold objects, indexed by their
``_name`` attributes.
:class:`ManifoldObjectFiniteFamily` instances are totally ordered according
to their lexicographically ordered element names.
The subclass :class:`ManifoldSubsetFiniteFamily` customizes the print
representation further.
"""
#*****************************************************************************
# Copyright (C) 2021 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************

from functools import total_ordering
from sage.sets.family import FiniteFamily

@total_ordering
class ManifoldObjectFiniteFamily(FiniteFamily):

r"""
Finite family of manifold objects, indexed by their names.
The class :class:`ManifoldObjectFiniteFamily` inherits from
:class:`FiniteFamily`. Therefore it is an associative container.
It provides specialized ``__repr__`` and ``_latex_`` methods.
:class:`ManifoldObjectFiniteFamily` instances are totally ordered
according to their lexicographically ordered element names.
EXAMPLES::
sage: from sage.manifolds.family import ManifoldObjectFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: C = B.subset('C')
sage: F = ManifoldObjectFiniteFamily([A, B, C]); F
Set {A, B, C} of objects of the 2-dimensional topological manifold M
sage: latex(F)
\{A, B, C\}
sage: F['B']
Subset B of the 2-dimensional topological manifold M
All objects must have the same base manifold::
sage: N = Manifold(2, 'N', structure='topological')
sage: ManifoldObjectFiniteFamily([M, N])
Traceback (most recent call last):
...
TypeError: all objects must have the same manifold
"""
def __init__(self, objects=(), keys=None):
r"""
Initialize a new instance of :class:`ManifoldObjectFiniteFamily`.
TESTS:
sage: from sage.manifolds.family import ManifoldObjectFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: C = B.subset('C')
sage: F = ManifoldObjectFiniteFamily([A, B, C]); F
Set {A, B, C} of objects of the 2-dimensional topological manifold M
sage: TestSuite(F).run(skip='_test_elements')
Like ``frozenset``, it can be created from any iterable::
sage: from sage.manifolds.family import ManifoldSubsetFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: I = M.subset('I')
sage: gen = (subset for subset in (M, I, M, I, M, I)); gen
<generator object ...>
sage: ManifoldSubsetFiniteFamily(gen)
Set {I, M} of subsets of the 2-dimensional topological manifold M
"""
if isinstance(objects, dict):
dictionary = objects
else:
dictionary = {object._name: object for object in objects}
if keys is None:
keys = sorted(dictionary.keys())
FiniteFamily.__init__(self, dictionary, keys)
names_and_latex_names = sorted((object._name, object._latex_name)
for object in self)
self._name = '{' + ', '.join(keys) + '}'
latex_names = (latex_name for name, latex_name in names_and_latex_names)
self._latex_name = r'\{' + ', '.join(latex_names) + r'\}'
try:
object_iter = iter(self)
self._manifold = next(object_iter)._manifold
except StopIteration:
self._manifold = None
else:
if not all(object._manifold == self._manifold for object in object_iter):
raise TypeError(f'all {self._repr_object_type()} must have the same manifold')

def _repr_object_type(self):
r"""
String that describes the type of the elements (plural).
TESTS::
sage: from sage.manifolds.family import ManifoldObjectFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: ManifoldObjectFiniteFamily([A, B]).__repr__() # indirect doctest
'Set {A, B} of objects of the 2-dimensional topological manifold M'
"""
return "objects"

def __lt__(self, other):
r"""
Implement the total order on instances of :class:`ManifoldObjectFiniteFamily`.
TESTS::
sage: from sage.manifolds.family import ManifoldSubsetFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: sorted([ManifoldSubsetFiniteFamily([A, B]), ManifoldSubsetFiniteFamily([]),
....: ManifoldSubsetFiniteFamily([B]), ManifoldSubsetFiniteFamily([A])])
[{},
Set {A} of subsets of the 2-dimensional topological manifold M,
Set {A, B} of subsets of the 2-dimensional topological manifold M,
Set {B} of subsets of the 2-dimensional topological manifold M]
"""
if not isinstance(other, ManifoldSubsetFiniteFamily):
return NotImplemented
return self.keys() < other.keys()

def __repr__(self):
r"""
String representation of the object.
TESTS::
sage: from sage.manifolds.family import ManifoldObjectFiniteFamily
sage: ManifoldObjectFiniteFamily().__repr__()
'{}'
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: ManifoldObjectFiniteFamily([A, B]).__repr__()
'Set {A, B} of objects of the 2-dimensional topological manifold M'
"""
if self:
return "Set {} of {} of the {}".format(self._name, self._repr_object_type(), self._manifold)
else:
return "{}"

def _latex_(self):
r"""
LaTeX representation of ``self``.
TESTS::
sage: from sage.manifolds.family import ManifoldSubsetFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: ManifoldSubsetFiniteFamily([B, A])._latex_()
'\\{A, B\\}'
"""
return self._latex_name

class ManifoldSubsetFiniteFamily(ManifoldObjectFiniteFamily):

r"""
Finite family of subsets of a topological manifold, indexed by their names.
The class :class:`ManifoldSubsetFiniteFamily` inherits from
:class:`ManifoldObjectFiniteFamily`. It provides an associative
container with specialized ``__repr__`` and ``_latex_`` methods.
:class:`ManifoldSubsetFiniteFamily` instances are totally ordered according
to their lexicographically ordered element (subset) names.
EXAMPLES::
sage: from sage.manifolds.family import ManifoldSubsetFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: C = B.subset('C')
sage: ManifoldSubsetFiniteFamily([A, B, C])
Set {A, B, C} of subsets of the 2-dimensional topological manifold M
sage: latex(_)
\{A, B, C\}
All subsets must have the same base manifold::
sage: N = Manifold(2, 'N', structure='topological')
sage: ManifoldSubsetFiniteFamily([M, N])
Traceback (most recent call last):
...
TypeError: all... subsets must have the same manifold
"""

def _repr_object_type(self):
r"""
String that describes the type of the elements (plural).
TESTS::
sage: from sage.manifolds.family import ManifoldSubsetFiniteFamily
sage: M = Manifold(2, 'M', structure='topological')
sage: A = M.subset('A')
sage: B = M.subset('B')
sage: ManifoldSubsetFiniteFamily([A, B]).__repr__() # indirect doctest
'Set {A, B} of subsets of the 2-dimensional topological manifold M'
"""
if all(subset.is_open() for subset in self):
return "open subsets"
else:
return "subsets"
Loading

0 comments on commit 5a072cf

Please sign in to comment.