passagemath-symbolics 10.6.37__cp310-cp310-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. passagemath_symbolics/__init__.py +3 -0
  2. passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
  3. passagemath_symbolics-10.6.37.dist-info/RECORD +171 -0
  4. passagemath_symbolics-10.6.37.dist-info/WHEEL +5 -0
  5. passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
  6. sage/all__sagemath_symbolics.py +17 -0
  7. sage/calculus/all.py +14 -0
  8. sage/calculus/calculus.py +2826 -0
  9. sage/calculus/desolvers.py +1866 -0
  10. sage/calculus/predefined.py +51 -0
  11. sage/calculus/tests.py +225 -0
  12. sage/calculus/var.cpython-310-x86_64-linux-gnu.so +0 -0
  13. sage/calculus/var.pyx +401 -0
  14. sage/dynamics/all__sagemath_symbolics.py +6 -0
  15. sage/dynamics/complex_dynamics/all.py +5 -0
  16. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  17. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-310-x86_64-linux-gnu.so +0 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
  19. sage/ext/all__sagemath_symbolics.py +1 -0
  20. sage/ext_data/kenzo/CP2.txt +45 -0
  21. sage/ext_data/kenzo/CP3.txt +349 -0
  22. sage/ext_data/kenzo/CP4.txt +4774 -0
  23. sage/ext_data/kenzo/README.txt +49 -0
  24. sage/ext_data/kenzo/S4.txt +20 -0
  25. sage/ext_data/magma/latex/latex.m +1021 -0
  26. sage/ext_data/magma/latex/latex.spec +1 -0
  27. sage/ext_data/magma/sage/basic.m +356 -0
  28. sage/ext_data/magma/sage/sage.spec +1 -0
  29. sage/ext_data/magma/spec +9 -0
  30. sage/geometry/all__sagemath_symbolics.py +8 -0
  31. sage/geometry/hyperbolic_space/all.py +5 -0
  32. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  39. sage/geometry/riemannian_manifolds/all.py +7 -0
  40. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  41. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  42. sage/interfaces/all__sagemath_symbolics.py +1 -0
  43. sage/interfaces/magma.py +3017 -0
  44. sage/interfaces/magma_free.py +92 -0
  45. sage/interfaces/maple.py +1397 -0
  46. sage/interfaces/mathematica.py +1345 -0
  47. sage/interfaces/mathics.py +1312 -0
  48. sage/interfaces/sympy.py +1398 -0
  49. sage/interfaces/sympy_wrapper.py +197 -0
  50. sage/interfaces/tides.py +938 -0
  51. sage/libs/all__sagemath_symbolics.py +6 -0
  52. sage/manifolds/all.py +7 -0
  53. sage/manifolds/calculus_method.py +555 -0
  54. sage/manifolds/catalog.py +437 -0
  55. sage/manifolds/chart.py +4019 -0
  56. sage/manifolds/chart_func.py +3419 -0
  57. sage/manifolds/continuous_map.py +2183 -0
  58. sage/manifolds/continuous_map_image.py +155 -0
  59. sage/manifolds/differentiable/affine_connection.py +2475 -0
  60. sage/manifolds/differentiable/all.py +1 -0
  61. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  62. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  63. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  64. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  65. sage/manifolds/differentiable/chart.py +1241 -0
  66. sage/manifolds/differentiable/curve.py +1028 -0
  67. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  68. sage/manifolds/differentiable/degenerate.py +559 -0
  69. sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
  70. sage/manifolds/differentiable/diff_form.py +1658 -0
  71. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  72. sage/manifolds/differentiable/diff_map.py +1315 -0
  73. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  74. sage/manifolds/differentiable/examples/all.py +1 -0
  75. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  76. sage/manifolds/differentiable/examples/real_line.py +897 -0
  77. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  78. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  79. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  80. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  81. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  82. sage/manifolds/differentiable/manifold.py +4254 -0
  83. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  84. sage/manifolds/differentiable/metric.py +3032 -0
  85. sage/manifolds/differentiable/mixed_form.py +1507 -0
  86. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  87. sage/manifolds/differentiable/multivector_module.py +800 -0
  88. sage/manifolds/differentiable/multivectorfield.py +1520 -0
  89. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  90. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  91. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  92. sage/manifolds/differentiable/scalarfield.py +1343 -0
  93. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  94. sage/manifolds/differentiable/symplectic_form.py +910 -0
  95. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  96. sage/manifolds/differentiable/tangent_space.py +412 -0
  97. sage/manifolds/differentiable/tangent_vector.py +616 -0
  98. sage/manifolds/differentiable/tensorfield.py +4665 -0
  99. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  100. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  101. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  102. sage/manifolds/differentiable/vector_bundle.py +1728 -0
  103. sage/manifolds/differentiable/vectorfield.py +1717 -0
  104. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  105. sage/manifolds/differentiable/vectorframe.py +1832 -0
  106. sage/manifolds/family.py +270 -0
  107. sage/manifolds/local_frame.py +1490 -0
  108. sage/manifolds/manifold.py +3090 -0
  109. sage/manifolds/manifold_homset.py +452 -0
  110. sage/manifolds/operators.py +359 -0
  111. sage/manifolds/point.py +994 -0
  112. sage/manifolds/scalarfield.py +3718 -0
  113. sage/manifolds/scalarfield_algebra.py +629 -0
  114. sage/manifolds/section.py +3111 -0
  115. sage/manifolds/section_module.py +831 -0
  116. sage/manifolds/structure.py +229 -0
  117. sage/manifolds/subset.py +2764 -0
  118. sage/manifolds/subsets/all.py +1 -0
  119. sage/manifolds/subsets/closure.py +131 -0
  120. sage/manifolds/subsets/pullback.py +885 -0
  121. sage/manifolds/topological_submanifold.py +891 -0
  122. sage/manifolds/trivialization.py +733 -0
  123. sage/manifolds/utilities.py +1348 -0
  124. sage/manifolds/vector_bundle.py +1342 -0
  125. sage/manifolds/vector_bundle_fiber.py +332 -0
  126. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  127. sage/matrix/all__sagemath_symbolics.py +1 -0
  128. sage/matrix/matrix_symbolic_dense.cpython-310-x86_64-linux-gnu.so +0 -0
  129. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  130. sage/matrix/matrix_symbolic_dense.pyx +1022 -0
  131. sage/matrix/matrix_symbolic_sparse.cpython-310-x86_64-linux-gnu.so +0 -0
  132. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  133. sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
  134. sage/modules/all__sagemath_symbolics.py +1 -0
  135. sage/modules/vector_callable_symbolic_dense.py +105 -0
  136. sage/modules/vector_symbolic_dense.py +116 -0
  137. sage/modules/vector_symbolic_sparse.py +118 -0
  138. sage/rings/all__sagemath_symbolics.py +4 -0
  139. sage/rings/asymptotic/all.py +6 -0
  140. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  141. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  142. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
  143. sage/rings/asymptotic/growth_group.py +5373 -0
  144. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  145. sage/rings/asymptotic/term_monoid.py +5237 -0
  146. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  147. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  148. sage/symbolic/all.py +15 -0
  149. sage/symbolic/assumptions.py +985 -0
  150. sage/symbolic/benchmark.py +93 -0
  151. sage/symbolic/callable.py +459 -0
  152. sage/symbolic/complexity_measures.py +35 -0
  153. sage/symbolic/constants.py +1287 -0
  154. sage/symbolic/expression_conversion_algebraic.py +310 -0
  155. sage/symbolic/expression_conversion_sympy.py +317 -0
  156. sage/symbolic/expression_conversions.py +1713 -0
  157. sage/symbolic/function_factory.py +355 -0
  158. sage/symbolic/integration/all.py +1 -0
  159. sage/symbolic/integration/external.py +270 -0
  160. sage/symbolic/integration/integral.py +1115 -0
  161. sage/symbolic/maxima_wrapper.py +162 -0
  162. sage/symbolic/operators.py +267 -0
  163. sage/symbolic/random_tests.py +462 -0
  164. sage/symbolic/relation.py +1907 -0
  165. sage/symbolic/ring.cpython-310-x86_64-linux-gnu.so +0 -0
  166. sage/symbolic/ring.pxd +5 -0
  167. sage/symbolic/ring.pyx +1396 -0
  168. sage/symbolic/subring.py +1025 -0
  169. sage/symbolic/symengine.py +19 -0
  170. sage/symbolic/tests.py +40 -0
  171. sage/symbolic/units.py +1470 -0
@@ -0,0 +1,885 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ r"""
3
+ Manifold Subsets Defined as Pullbacks of Subsets under Continuous Maps
4
+ """
5
+
6
+
7
+ # ****************************************************************************
8
+ # Copyright (C) 2021 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
9
+ #
10
+ # This program is free software: you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation, either version 2 of the License, or
13
+ # (at your option) any later version.
14
+ # https://www.gnu.org/licenses/
15
+ # ****************************************************************************
16
+
17
+ import sage.geometry.abc
18
+ from sage.categories.metric_spaces import MetricSpaces
19
+ from sage.categories.sets_cat import EmptySetError, Sets
20
+ from sage.manifolds.chart import Chart
21
+ from sage.manifolds.scalarfield import ScalarField
22
+ from sage.manifolds.subset import ManifoldSubset
23
+ from sage.misc.lazy_import import lazy_import
24
+ from sage.modules.free_module import FreeModule_generic
25
+ from sage.modules.free_module_element import vector
26
+ from sage.rings.complex_double import CDF
27
+ from sage.rings.infinity import infinity, minus_infinity
28
+ from sage.rings.integer_ring import ZZ
29
+ from sage.rings.rational_field import QQ
30
+ from sage.rings.real_double import RDF
31
+ from sage.rings.real_lazy import CLF, RLF
32
+ from sage.sets.real_set import RealSet
33
+ from sage.symbolic.ring import SR
34
+
35
+ lazy_import('sage.geometry.relative_interior', 'RelativeInterior')
36
+
37
+
38
+ class ManifoldSubsetPullback(ManifoldSubset):
39
+ """
40
+ Manifold subset defined as a pullback of a subset under a continuous map.
41
+
42
+ INPUT:
43
+
44
+ - ``map`` -- an instance of :class:`~sage.manifolds.continuous_map.ContinuousMap`,
45
+ :class:`ScalarField`, or :class:`Chart`
46
+
47
+ - ``codomain_subset`` -- an instance of :class:`~sage.manifolds.subset.ManifoldSubset`,
48
+ :class:`RealSet`, or :class:`~sage.geometry.convex_set.ConvexSet_base`
49
+
50
+ EXAMPLES::
51
+
52
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
53
+ sage: M = Manifold(2, 'R^2', structure='topological')
54
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
55
+
56
+ Pulling back a real interval under a scalar field::
57
+
58
+ sage: r_squared = M.scalar_field(x^2+y^2)
59
+ sage: r_squared.set_immutable()
60
+ sage: cl_I = RealSet([1, 4]); cl_I
61
+ [1, 4]
62
+ sage: cl_O = ManifoldSubsetPullback(r_squared, cl_I); cl_O
63
+ Subset f_inv_[1, 4] of the 2-dimensional topological manifold R^2
64
+ sage: M.point((0, 0)) in cl_O
65
+ False
66
+ sage: M.point((0, 1)) in cl_O
67
+ True
68
+
69
+ Pulling back an open real interval gives an open subset::
70
+
71
+ sage: I = RealSet((1, 4)); I
72
+ (1, 4)
73
+ sage: O = ManifoldSubsetPullback(r_squared, I); O
74
+ Open subset f_inv_(1, 4) of the 2-dimensional topological manifold R^2
75
+ sage: M.point((1, 0)) in O
76
+ False
77
+ sage: M.point((1, 1)) in O
78
+ True
79
+
80
+ Pulling back a polytope under a chart::
81
+
82
+ sage: # needs sage.geometry.polyhedron
83
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 2], [2, 1]]); P
84
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
85
+ sage: S = ManifoldSubsetPullback(c_cart, P); S
86
+ Subset x_y_inv_P of the 2-dimensional topological manifold R^2
87
+ sage: M((1, 2)) in S
88
+ True
89
+ sage: M((2, 0)) in S
90
+ False
91
+
92
+ Pulling back the interior of a polytope under a chart::
93
+
94
+ sage: # needs sage.geometry.polyhedron
95
+ sage: int_P = P.interior(); int_P
96
+ Relative interior of a
97
+ 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
98
+ sage: int_S = ManifoldSubsetPullback(c_cart, int_P, name='int_S'); int_S
99
+ Open subset int_S of the 2-dimensional topological manifold R^2
100
+ sage: M((0, 0)) in int_S
101
+ False
102
+ sage: M((1, 1)) in int_S
103
+ True
104
+
105
+ Using the embedding map of a submanifold::
106
+
107
+ sage: M = Manifold(3, 'M', structure='topological')
108
+ sage: N = Manifold(2, 'N', ambient=M, structure='topological'); N
109
+ 2-dimensional topological submanifold N
110
+ immersed in the 3-dimensional topological manifold M
111
+ sage: CM.<x,y,z> = M.chart()
112
+ sage: CN.<u,v> = N.chart()
113
+ sage: t = var('t')
114
+ sage: phi = N.continuous_map(M, {(CN,CM): [u,v,t+u^2+v^2]})
115
+ sage: phi_inv = M.continuous_map(N, {(CM,CN): [x,y]})
116
+ sage: phi_inv_t = M.scalar_field({CM: z-x^2-y^2})
117
+ sage: N.set_immersion(phi, inverse=phi_inv, var=t,
118
+ ....: t_inverse={t: phi_inv_t})
119
+ sage: N.declare_embedding()
120
+
121
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
122
+ sage: S = M.open_subset('S', coord_def={CM: z<1})
123
+ sage: phi_without_t = N.continuous_map(M, {(CN, CM): [expr.subs(t=0)
124
+ ....: for expr in phi.expr()]})
125
+ sage: phi_without_t
126
+ Continuous map
127
+ from the 2-dimensional topological submanifold N
128
+ embedded in the 3-dimensional topological manifold M
129
+ to the 3-dimensional topological manifold M
130
+ sage: phi_without_t.expr()
131
+ (u, v, u^2 + v^2)
132
+ sage: D = ManifoldSubsetPullback(phi_without_t, S); D
133
+ Subset f_inv_S of the 2-dimensional topological submanifold N
134
+ embedded in the 3-dimensional topological manifold M
135
+ sage: N.point((2,0)) in D
136
+ False
137
+ """
138
+ @staticmethod
139
+ def __classcall_private__(cls, map, codomain_subset, inverse=None,
140
+ name=None, latex_name=None):
141
+ """
142
+ Normalize arguments and delegate to other constructors.
143
+
144
+ TESTS::
145
+
146
+ sage: # needs sage.geometry.polyhedron
147
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
148
+ sage: M = Manifold(2, 'R^2', structure='topological')
149
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
150
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 2], [3, 4]]); P
151
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
152
+ sage: S = ManifoldSubsetPullback(c_cart, P); S
153
+ Subset x_y_inv_P of the 2-dimensional topological manifold R^2
154
+ sage: S is ManifoldSubsetPullback(c_cart, P)
155
+ True
156
+ """
157
+
158
+ try:
159
+ is_mutable = map.is_mutable()
160
+ except AttributeError:
161
+ pass
162
+ else:
163
+ if is_mutable:
164
+ map = map.copy()
165
+ map.set_immutable()
166
+ try:
167
+ is_mutable = inverse.is_mutable()
168
+ except AttributeError:
169
+ pass
170
+ else:
171
+ if is_mutable:
172
+ inverse = inverse.copy()
173
+ inverse.set_immutable()
174
+
175
+ if inverse is None:
176
+ if isinstance(map, Chart):
177
+ from sage.misc.latex import latex
178
+ inverse_latex_name = '(' + ','.join(str(latex(x)) + '^{-1}' for x in map) + ')'
179
+ inverse_name = '_'.join(repr(x) for x in map) + '_inv'
180
+ else:
181
+ map_name = map._name or 'f'
182
+ map_latex_name = map._latex_name or map_name
183
+ inverse_name = map_name + '_inv'
184
+ inverse_latex_name = map_latex_name + r'^{-1}'
185
+ else:
186
+ inverse_name = inverse._name
187
+ inverse_latex_name = inverse._latex_name
188
+ try:
189
+ codomain_subset_latex_name = codomain_subset._latex_name
190
+ codomain_subset_name = codomain_subset._name
191
+ except AttributeError:
192
+ from sage.misc.latex import latex
193
+ codomain_subset_latex_name = str(latex(codomain_subset))
194
+ s = repr(codomain_subset)
195
+ if len(s) > 10:
196
+ codomain_subset_name = 'P'
197
+ else:
198
+ codomain_subset_name = s
199
+ if latex_name is None:
200
+ if name is None:
201
+ latex_name = inverse_latex_name + '(' + codomain_subset_latex_name + ')'
202
+ else:
203
+ latex_name = name
204
+ if name is None:
205
+ name = inverse_name + '_' + codomain_subset_name
206
+
207
+ if cls._is_open(codomain_subset):
208
+
209
+ try:
210
+ coord_def = cls._coord_def(map, codomain_subset)
211
+ except NotImplementedError:
212
+ pass
213
+ else:
214
+ return map.domain().open_subset(name=name, latex_name=latex_name,
215
+ coord_def=coord_def)
216
+
217
+ self = super().__classcall__(cls, map, codomain_subset, inverse, name, latex_name)
218
+
219
+ return self
220
+
221
+ @staticmethod
222
+ def _is_open(codomain_subset):
223
+ """
224
+ Return whether ``codomain_subset`` is (known to be) an open subset of its ambient space.
225
+
226
+ EXAMPLES:
227
+
228
+ Manifolds and subsets::
229
+
230
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
231
+ sage: R2 = Manifold(2, 'R^2', structure='topological'); R2
232
+ 2-dimensional topological manifold R^2
233
+ sage: ManifoldSubsetPullback._is_open(R2)
234
+ True
235
+ sage: A = R2.subset('A'); A
236
+ Subset A of the 2-dimensional topological manifold R^2
237
+ sage: ManifoldSubsetPullback._is_open(A)
238
+ False
239
+
240
+ :class:`RealSet` instances::
241
+
242
+ sage: I = RealSet.open(1, 2); I
243
+ (1, 2)
244
+ sage: ManifoldSubsetPullback._is_open(I)
245
+ True
246
+ sage: cl_I = RealSet.closed(1, 2); cl_I
247
+ [1, 2]
248
+ sage: ManifoldSubsetPullback._is_open(cl_I)
249
+ False
250
+
251
+ Polyhedra::
252
+
253
+ sage: # needs sage.geometry.polyhedron
254
+ sage: Empty = Polyhedron(ambient_dim=2); Empty
255
+ The empty polyhedron in ZZ^2
256
+ sage: ManifoldSubsetPullback._is_open(Empty)
257
+ True
258
+ sage: C = polytopes.cube(); C
259
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
260
+ sage: ManifoldSubsetPullback._is_open(C)
261
+ False
262
+
263
+ Interiors of polyhedra::
264
+
265
+ sage: int_C = C.interior(); int_C # needs sage.geometry.polyhedron
266
+ Relative interior of a
267
+ 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
268
+ sage: ManifoldSubsetPullback._is_open(int_C) # needs sage.geometry.polyhedron
269
+ True
270
+
271
+ PPL polyhedra and not-necessarily-closed polyhedra::
272
+
273
+ sage: # needs pplpy
274
+ sage: from ppl import Variable, C_Polyhedron, NNC_Polyhedron, Constraint_System
275
+ sage: u = Variable(0)
276
+ sage: v = Variable(1)
277
+ sage: CS = Constraint_System()
278
+ sage: CS.insert(0 < u)
279
+ sage: CS.insert(u < 1)
280
+ sage: CS.insert(0 < v)
281
+ sage: CS.insert(v < 1)
282
+ sage: CS.insert(u + v <= 3) # redundant inequality
283
+ sage: P = NNC_Polyhedron(CS); P
284
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 4 closure_points
285
+ sage: ManifoldSubsetPullback._is_open(P)
286
+ True
287
+ sage: CS.insert(u + v <= 1)
288
+ sage: T = NNC_Polyhedron(CS); T
289
+ A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 point, 3 closure_points
290
+ sage: ManifoldSubsetPullback._is_open(T)
291
+ False
292
+ """
293
+
294
+ if isinstance(codomain_subset, ManifoldSubset):
295
+ return codomain_subset.is_open()
296
+
297
+ if isinstance(codomain_subset, RealSet):
298
+ return codomain_subset.is_open()
299
+
300
+ if isinstance(codomain_subset, sage.geometry.abc.Polyhedron):
301
+ return codomain_subset.is_empty() or codomain_subset.is_universe()
302
+
303
+ if isinstance(codomain_subset, RelativeInterior):
304
+ return codomain_subset.closure().is_full_dimensional()
305
+
306
+ if codomain_subset in Sets().Finite():
307
+ return codomain_subset.cardinality() == 0
308
+
309
+ if hasattr(codomain_subset, 'minimized_constraints'):
310
+ try:
311
+ from ppl import C_Polyhedron, NNC_Polyhedron
312
+ except ImportError:
313
+ pass
314
+ else:
315
+ if isinstance(codomain_subset, (NNC_Polyhedron, C_Polyhedron)):
316
+ cs = codomain_subset.minimized_constraints()
317
+ if cs.has_equalities():
318
+ return False
319
+ if any(constraint.is_nonstrict_inequality()
320
+ for constraint in cs):
321
+ return False
322
+ return True
323
+
324
+ return False
325
+
326
+ @staticmethod
327
+ def _interval_restriction(expr, interval):
328
+ """
329
+ Return a restriction expressing that ``expr`` lies in ``interval``.
330
+
331
+ INPUT:
332
+
333
+ - ``expr`` -- a symbolic expression
334
+ - ``interval`` -- an instance of :class:`~sage.sets.real_set.InternalRealInterval`
335
+
336
+ OUTPUT:
337
+
338
+ - A restriction suitable as input to :meth:`~sage.manifolds.chart.restrict`:
339
+ lists are conjunctions, tuples are disjunctions
340
+
341
+ EXAMPLES::
342
+
343
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
344
+ sage: _interval_restriction = ManifoldSubsetPullback._interval_restriction
345
+ sage: var('t')
346
+ t
347
+ sage: assume(t >= -2)
348
+ sage: assume(t <= 5)
349
+ sage: _interval_restriction(t, RealSet(3, 4)[0])
350
+ [t > 3, t < 4]
351
+ sage: _interval_restriction(t, RealSet.unbounded_below_closed(2)[0])
352
+ t <= 2
353
+ sage: _interval_restriction(t, RealSet.closed(-5, 5)[0])
354
+ []
355
+ sage: _interval_restriction(t, RealSet.unbounded_below_closed(-5)[0])
356
+ ()
357
+ sage: _interval_restriction(t, RealSet.unbounded_above_closed(6)[0])
358
+ ()
359
+ sage: _interval_restriction(t^2, RealSet.unbounded_above_closed(0)[0])
360
+ []
361
+ """
362
+
363
+ conjunction = []
364
+ if interval.lower() != minus_infinity:
365
+ if interval.lower_closed():
366
+ condition = (expr >= interval.lower())
367
+ negation = (expr < interval.lower())
368
+ else:
369
+ condition = (expr > interval.lower())
370
+ negation = (expr <= interval.lower())
371
+ if negation:
372
+ # known to be false
373
+ return ()
374
+ if not condition:
375
+ # not known to be true
376
+ conjunction.append(condition)
377
+
378
+ if interval.upper() != infinity:
379
+ if interval.upper_closed():
380
+ condition = (expr <= interval.upper())
381
+ negation = (expr > interval.upper())
382
+ else:
383
+ condition = (expr < interval.upper())
384
+ negation = (expr >= interval.upper())
385
+ if negation:
386
+ # known to be false
387
+ return ()
388
+ if not condition:
389
+ # not known to be true
390
+ conjunction.append(condition)
391
+
392
+ if len(conjunction) == 1:
393
+ return conjunction[0]
394
+ else:
395
+ # lists express 'and'
396
+ return conjunction
397
+
398
+ @staticmethod
399
+ def _realset_restriction(expr, realset):
400
+ """
401
+ Return a restriction expressing that ``expr`` lies in ``realset``.
402
+
403
+ INPUT:
404
+
405
+ - ``expr`` -- a symbolic expression
406
+ - ``interval`` -- an instance of :class:`~sage.sets.real_set.RealSet`
407
+
408
+ OUTPUT:
409
+
410
+ - A restriction suitable as input to :meth:`~sage.manifolds.chart.restrict`:
411
+ lists are conjunctions, tuples are disjunctions
412
+
413
+ EXAMPLES::
414
+
415
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
416
+ sage: _realset_restriction = ManifoldSubsetPullback._realset_restriction
417
+ sage: var('t')
418
+ t
419
+ sage: assume(t >= -2)
420
+ sage: assume(t <= 5)
421
+ sage: _realset_restriction(t, RealSet(-oo, oo))
422
+ []
423
+ sage: _realset_restriction(t, RealSet())
424
+ ()
425
+ sage: _realset_restriction(t, RealSet([-5, -4], (-1, 1), [3, 4], [6, 7]))
426
+ ([t > -1, t < 1], [t >= 3, t <= 4])
427
+ """
428
+ disjunction = []
429
+ for interval in realset:
430
+ condition = ManifoldSubsetPullback._interval_restriction(expr, interval)
431
+ if condition == []:
432
+ return []
433
+ if condition != ():
434
+ disjunction.append(condition)
435
+
436
+ if len(disjunction) == 1:
437
+ return disjunction[0]
438
+ else:
439
+ # tuples express 'or'
440
+ return tuple(disjunction)
441
+
442
+ @staticmethod
443
+ def _polyhedron_restriction(expr, polyhedron, relint=False):
444
+ """
445
+ Return a restriction expressing that ``expr`` lies in ``polyhedron`` or its relative interior.
446
+
447
+ INPUT:
448
+
449
+ - ``expr`` -- a symbolic expression
450
+ - ``polyhedron`` -- an instance of :class:`~sage.geometry.polyhedron.base.Polyhedron_base`
451
+ - ``relint`` -- whether the restriction should use the relative interior
452
+
453
+ OUTPUT:
454
+
455
+ - A restriction suitable as input to :meth:`~sage.manifolds.chart.restrict`:
456
+ lists are conjunctions, tuples are disjunctions
457
+
458
+ EXAMPLES::
459
+
460
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
461
+ sage: _polyhedron_restriction = ManifoldSubsetPullback._polyhedron_restriction
462
+ sage: var('x y z')
463
+ (x, y, z)
464
+ sage: c = polytopes.cube() # needs sage.geometry.polyhedron
465
+ sage: _polyhedron_restriction((x, y, z), c) # needs sage.geometry.polyhedron
466
+ [-x + 1 >= 0, -y + 1 >= 0, -z + 1 >= 0, x + 1 >= 0, z + 1 >= 0, y + 1 >= 0]
467
+ sage: _polyhedron_restriction((x, y, z), c, relint=True) # needs sage.geometry.polyhedron
468
+ [-x + 1 > 0, -y + 1 > 0, -z + 1 > 0, x + 1 > 0, z + 1 > 0, y + 1 > 0]
469
+ """
470
+ conjunction = []
471
+
472
+ expr = vector(SR, expr)
473
+ for constraint in polyhedron.Hrepresentation():
474
+
475
+ if constraint.is_inequality():
476
+ if relint:
477
+ condition = (constraint.eval(expr) > 0)
478
+ else:
479
+ condition = (constraint.eval(expr) >= 0)
480
+ else:
481
+ condition = (constraint.eval(expr) == 0)
482
+ if not condition:
483
+ # not known to be true
484
+ conjunction.append(condition)
485
+
486
+ if len(conjunction) == 1:
487
+ return conjunction[0]
488
+ else:
489
+ # lists express 'and'
490
+ return conjunction
491
+
492
+ @staticmethod
493
+ def _coord_def(map, codomain_subset):
494
+ r"""
495
+ Return a coordinate definition of the open subset that is the pullback of ``codomain_subset``.
496
+
497
+ INPUT:
498
+
499
+ - ``map`` -- an instance of :class:`ScalarField` or :class:`Chart`
500
+
501
+ - ``codomain_subset`` -- if ``map`` is a :class:`ScalarField`, an
502
+ instance of :class:`RealSet`; if ``map`` is a :class:`Chart`, the
503
+ relative interior of a polyhedron
504
+
505
+ For other inputs, a :exc:`NotImplementedError` will be raised.
506
+
507
+ OUTPUT:
508
+
509
+ - an object suitable for the parameter ``coord_def`` of
510
+ :meth:`sage.manifolds.manifold.TopologicalManifold.open_subset`.
511
+
512
+ EXAMPLES::
513
+
514
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
515
+ sage: _coord_def = ManifoldSubsetPullback._coord_def
516
+ sage: M = Manifold(2, 'R^2', structure='topological')
517
+
518
+ Coordinate definition of an open chart polyhedron::
519
+
520
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
521
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 2], [3, 4]]); P # needs sage.geometry.polyhedron
522
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
523
+ sage: ri_P = P.relative_interior(); ri_P # needs sage.geometry.polyhedron
524
+ Relative interior of a 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
525
+ sage: _coord_def(c_cart, ri_P) # needs sage.geometry.polyhedron
526
+ {Chart (R^2, (x, y)): [2*x - y > 0, -4*x + 3*y > 0, x - y + 1 > 0]}
527
+
528
+ Coordinate definition of the pullback of an open interval under a scalar field::
529
+
530
+ sage: r_squared = M.scalar_field(x^2 + y^2)
531
+ sage: I = RealSet((1, 4)); I
532
+ (1, 4)
533
+ sage: _coord_def(r_squared, I)
534
+ {Chart (R^2, (x, y)): [x^2 + y^2 > 1, x^2 + y^2 < 4]}
535
+ """
536
+ if isinstance(map, ScalarField) and isinstance(codomain_subset, RealSet):
537
+
538
+ return {chart: ManifoldSubsetPullback._realset_restriction(func.expr(),
539
+ codomain_subset)
540
+ for chart, func in map._express.items()}
541
+
542
+ if isinstance(map, Chart):
543
+
544
+ chart = map
545
+
546
+ if isinstance(codomain_subset, RealSet):
547
+ return {chart: ManifoldSubsetPullback._realset_restriction(chart[0],
548
+ codomain_subset)}
549
+
550
+ if isinstance(codomain_subset, RelativeInterior) and isinstance(codomain_subset.closure(), sage.geometry.abc.Polyhedron):
551
+ return {chart: ManifoldSubsetPullback._polyhedron_restriction(
552
+ chart, codomain_subset.closure(), relint=True)}
553
+
554
+ raise NotImplementedError
555
+
556
+ def __init__(self, map, codomain_subset, inverse, name, latex_name):
557
+ r"""
558
+ Construct a manifold subset that is a pullback.
559
+
560
+ TESTS::
561
+
562
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
563
+ sage: M = Manifold(2, 'R^2', structure='topological')
564
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
565
+ sage: r_squared = M.scalar_field(x^2+y^2)
566
+ sage: r_squared.set_immutable()
567
+ sage: cl_I = RealSet([1, 4]); cl_I
568
+ [1, 4]
569
+ sage: cl_O = ManifoldSubsetPullback(r_squared, cl_I); cl_O
570
+ Subset f_inv_[1, 4] of the 2-dimensional topological manifold R^2
571
+ sage: TestSuite(cl_O).run(skip='_test_elements')
572
+ """
573
+ if inverse is None and isinstance(map, Chart):
574
+ chart = map
575
+ scalar_codomain = (isinstance(codomain_subset, RealSet)
576
+ or any(field.has_coerce_map_from(codomain_subset)
577
+ for field in (CDF, RDF, CLF, RLF)))
578
+ if scalar_codomain:
579
+ if chart.domain().dimension() != 1:
580
+ raise ValueError('to pull back a set of scalars by a chart, the manifold must be 1-dimensional')
581
+ map = chart.domain().scalar_field({chart: chart[0]})
582
+
583
+ def _inverse(coord):
584
+ return self.point((coord,), chart=chart)
585
+ else:
586
+ def _inverse(coords):
587
+ return self.point(coords, chart=map)
588
+ inverse = _inverse
589
+
590
+ self._map = map
591
+ self._inverse = inverse
592
+
593
+ self._codomain_subset = codomain_subset
594
+ base_manifold = map.domain()
595
+ ManifoldSubset.__init__(self, base_manifold, name, latex_name=latex_name)
596
+
597
+ def _an_element_(self):
598
+ r"""
599
+ Construct some point in ``self``.
600
+
601
+ EXAMPLES::
602
+
603
+ sage: # needs sage.geometry.polyhedron
604
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
605
+ sage: M = Manifold(3, 'R^3', structure='topological')
606
+ sage: c_cart.<x,y,z> = M.chart() # Cartesian coordinates on R^3
607
+ sage: Cube = polytopes.cube(); Cube
608
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
609
+ sage: McCube = ManifoldSubsetPullback(c_cart, Cube, name='McCube'); McCube
610
+ Subset McCube of the 3-dimensional topological manifold R^3
611
+ sage: p = McCube.an_element(); p
612
+ Point on the 3-dimensional topological manifold R^3
613
+ sage: p.coordinates(c_cart)
614
+ (0, 0, 0)
615
+
616
+ sage: # needs sage.geometry.polyhedron
617
+ sage: Empty = Polyhedron(ambient_dim=3)
618
+ sage: McEmpty = ManifoldSubsetPullback(c_cart, Empty, name='McEmpty')
619
+ sage: McEmpty
620
+ Subset McEmpty of the 3-dimensional topological manifold R^3
621
+ sage: McEmpty.an_element()
622
+ Traceback (most recent call last):
623
+ ...
624
+ sage.categories.sets_cat.EmptySetError
625
+ """
626
+ try:
627
+ return next(iter(self.some_elements()))
628
+ except StopIteration:
629
+ raise EmptySetError
630
+
631
+ def some_elements(self):
632
+ r"""
633
+ Generate some elements of ``self``.
634
+
635
+ EXAMPLES::
636
+
637
+ sage: # needs sage.geometry.polyhedron
638
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
639
+ sage: M = Manifold(3, 'R^3', structure='topological')
640
+ sage: c_cart.<x,y,z> = M.chart() # Cartesian coordinates on R^3
641
+ sage: Cube = polytopes.cube(); Cube
642
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
643
+ sage: McCube = ManifoldSubsetPullback(c_cart, Cube, name='McCube'); McCube
644
+ Subset McCube of the 3-dimensional topological manifold R^3
645
+ sage: L = list(McCube.some_elements()); L
646
+ [Point on the 3-dimensional topological manifold R^3,
647
+ Point on the 3-dimensional topological manifold R^3,
648
+ Point on the 3-dimensional topological manifold R^3,
649
+ Point on the 3-dimensional topological manifold R^3,
650
+ Point on the 3-dimensional topological manifold R^3,
651
+ Point on the 3-dimensional topological manifold R^3]
652
+ sage: list(p.coordinates(c_cart) for p in L)
653
+ [(0, 0, 0),
654
+ (1, -1, -1),
655
+ (1, 0, -1),
656
+ (1, 1/2, 0),
657
+ (1, -1/4, 1/2),
658
+ (0, -5/8, 3/4)]
659
+
660
+ sage: # needs sage.geometry.polyhedron
661
+ sage: Empty = Polyhedron(ambient_dim=3)
662
+ sage: McEmpty = ManifoldSubsetPullback(c_cart, Empty, name='McEmpty')
663
+ sage: McEmpty
664
+ Subset McEmpty of the 3-dimensional topological manifold R^3
665
+ sage: list(McEmpty.some_elements())
666
+ []
667
+ """
668
+ if self._inverse is not None:
669
+ for y in self._codomain_subset.some_elements():
670
+ yield self._inverse(y)
671
+ elif self.is_empty():
672
+ return
673
+ else:
674
+ # Fallback
675
+ p = super()._an_element_()
676
+ if p in self:
677
+ yield p
678
+
679
+ def __contains__(self, point):
680
+ r"""
681
+ Check whether ``point`` is contained in ``self``.
682
+
683
+ EXAMPLES::
684
+
685
+ sage: # needs sage.geometry.polyhedron
686
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
687
+ sage: M = Manifold(3, 'R^3', structure='topological')
688
+ sage: c_cart.<x,y,z> = M.chart() # Cartesian coordinates on R^3
689
+ sage: Cube = polytopes.cube(); Cube
690
+ A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices
691
+ sage: Cube.vertices_list()
692
+ [[1, -1, -1],
693
+ [1, 1, -1],
694
+ [1, 1, 1],
695
+ [1, -1, 1],
696
+ [-1, -1, 1],
697
+ [-1, -1, -1],
698
+ [-1, 1, -1],
699
+ [-1, 1, 1]]
700
+ sage: McCube = ManifoldSubsetPullback(c_cart, Cube, name='McCube'); McCube
701
+ Subset McCube of the 3-dimensional topological manifold R^3
702
+ sage: p = M.point((0, 0, 0)); p
703
+ Point on the 3-dimensional topological manifold R^3
704
+ sage: p in McCube
705
+ True
706
+ sage: q = M.point((2, 3, 4)); q
707
+ Point on the 3-dimensional topological manifold R^3
708
+ sage: q in McCube
709
+ False
710
+ """
711
+ if super().__contains__(point):
712
+ return True
713
+ coords = self._map(point)
714
+ if isinstance(coords, (tuple, list)):
715
+ coords = vector(coords)
716
+ return coords in self._codomain_subset
717
+
718
+ def is_open(self):
719
+ """
720
+ Return if ``self`` is (known to be) an open set.
721
+
722
+ This version of the method always returns ``False``.
723
+
724
+ Because the map is continuous, the pullback is open if the
725
+ ``codomain_subset`` is open.
726
+
727
+ However, the design of :class:`~sage.manifolds.subset.ManifoldSubset` requires that open subsets
728
+ are instances of the subclass :class:`sage.manifolds.manifold.TopologicalManifold`.
729
+ The constructor of :class:`ManifoldSubsetPullback` delegates to a subclass
730
+ of :class:`sage.manifolds.manifold.TopologicalManifold` for some open subsets.
731
+
732
+ EXAMPLES::
733
+
734
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
735
+ sage: M = Manifold(2, 'R^2', structure='topological')
736
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
737
+
738
+ sage: # needs sage.geometry.polyhedron
739
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 2], [3, 4]]); P
740
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
741
+ sage: P.is_open()
742
+ False
743
+ sage: McP = ManifoldSubsetPullback(c_cart, P, name='McP'); McP
744
+ Subset McP of the 2-dimensional topological manifold R^2
745
+ sage: McP.is_open()
746
+ False
747
+ """
748
+ return super().is_open()
749
+
750
+ def is_closed(self):
751
+ """
752
+ Return if ``self`` is (known to be) a closed subset of the manifold.
753
+
754
+ EXAMPLES::
755
+
756
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
757
+ sage: M = Manifold(2, 'R^2', structure='topological')
758
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
759
+
760
+ The pullback of a closed real interval under a scalar field is closed::
761
+
762
+ sage: r_squared = M.scalar_field(x^2+y^2)
763
+ sage: r_squared.set_immutable()
764
+ sage: cl_I = RealSet([1, 2]); cl_I
765
+ [1, 2]
766
+ sage: cl_O = ManifoldSubsetPullback(r_squared, cl_I); cl_O
767
+ Subset f_inv_[1, 2] of the 2-dimensional topological manifold R^2
768
+ sage: cl_O.is_closed()
769
+ True
770
+
771
+ The pullback of a (closed convex) polyhedron under a chart is closed::
772
+
773
+ sage: # needs sage.geometry.polyhedron
774
+ sage: P = Polyhedron(vertices=[[0, 0], [1, 2], [3, 4]]); P
775
+ A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 3 vertices
776
+ sage: McP = ManifoldSubsetPullback(c_cart, P, name='McP'); McP
777
+ Subset McP of the 2-dimensional topological manifold R^2
778
+ sage: McP.is_closed()
779
+ True
780
+
781
+ The pullback of real vector subspaces under a chart is closed::
782
+
783
+ sage: V = span([[1, 2]], RR); V
784
+ Vector space of degree 2 and dimension 1 over Real Field with 53 bits of precision
785
+ Basis matrix:
786
+ [1.00000000000000 2.00000000000000]
787
+ sage: McV = ManifoldSubsetPullback(c_cart, V, name='McV'); McV
788
+ Subset McV of the 2-dimensional topological manifold R^2
789
+ sage: McV.is_closed()
790
+ True
791
+
792
+ The pullback of point lattices under a chart is closed::
793
+
794
+ sage: W = span([[1, 0], [3, 5]], ZZ); W
795
+ Free module of degree 2 and rank 2 over Integer Ring
796
+ Echelon basis matrix:
797
+ [1 0]
798
+ [0 5]
799
+ sage: McW = ManifoldSubsetPullback(c_cart, W, name='McW'); McW
800
+ Subset McW of the 2-dimensional topological manifold R^2
801
+ sage: McW.is_closed()
802
+ True
803
+
804
+ The pullback of finite sets is closed::
805
+
806
+ sage: F = Family([vector(QQ, [1, 2], immutable=True), vector(QQ, [2, 3], immutable=True)])
807
+ sage: McF = ManifoldSubsetPullback(c_cart, F, name='McF'); McF
808
+ Subset McF of the 2-dimensional topological manifold R^2
809
+ sage: McF.is_closed()
810
+ True
811
+ """
812
+ if self.manifold().dimension() == 0:
813
+ return True
814
+ if isinstance(self._codomain_subset, ManifoldSubset):
815
+ if self._codomain_subset.is_closed():
816
+ # known closed
817
+ return True
818
+ elif isinstance(self._codomain_subset, RealSet):
819
+ # RealSet can decide closedness authoritatively
820
+ return self._codomain_subset.is_closed()
821
+ elif isinstance(self._codomain_subset, sage.geometry.abc.Polyhedron):
822
+ # Regardless of their base_ring, we treat polyhedra as closed
823
+ # convex subsets of R^n
824
+ return True
825
+ elif isinstance(self._codomain_subset, FreeModule_generic) and self._codomain_subset.rank() != infinity:
826
+ if self._codomain_subset.base_ring() in MetricSpaces().Complete():
827
+ # Closed topological vector subspace
828
+ return True
829
+ if self._codomain_subset.base_ring() == ZZ:
830
+ if self._codomain_subset.coordinate_ring().is_subring(QQ):
831
+ # Discrete subgroup of R^n
832
+ return True
833
+ if self._codomain_subset.rank() == self._codomain_subset.base_extend(RR).dimension():
834
+ # Discrete subgroup of R^n
835
+ return True
836
+ elif self._codomain_subset in Sets().Finite():
837
+ return True
838
+ else:
839
+ if hasattr(self._codomain_subset, 'is_topologically_closed'):
840
+ try:
841
+ from ppl import C_Polyhedron, NNC_Polyhedron
842
+ except ImportError:
843
+ pass
844
+ else:
845
+ if isinstance(self._codomain_subset, (NNC_Polyhedron, C_Polyhedron)):
846
+ # ppl polyhedra can decide closedness authoritatively
847
+ return self._codomain_subset.is_topologically_closed()
848
+ return super().is_closed()
849
+
850
+ def closure(self, name=None, latex_name=None):
851
+ """
852
+ Return the topological closure of ``self`` in the manifold.
853
+
854
+ Because ``self`` is a pullback of some subset under a continuous map,
855
+ the closure of ``self`` is the pullback of the closure.
856
+
857
+ EXAMPLES::
858
+
859
+ sage: from sage.manifolds.subsets.pullback import ManifoldSubsetPullback
860
+ sage: M = Manifold(2, 'R^2', structure='topological')
861
+ sage: c_cart.<x,y> = M.chart() # Cartesian coordinates on R^2
862
+ sage: r_squared = M.scalar_field(x^2+y^2)
863
+ sage: r_squared.set_immutable()
864
+ sage: I = RealSet.open_closed(1, 2); I
865
+ (1, 2]
866
+ sage: O = ManifoldSubsetPullback(r_squared, I); O
867
+ Subset f_inv_(1, 2] of the 2-dimensional topological manifold R^2
868
+ sage: latex(O)
869
+ f^{-1}((1, 2])
870
+ sage: cl_O = O.closure(); cl_O
871
+ Subset f_inv_[1, 2] of the 2-dimensional topological manifold R^2
872
+ sage: cl_O.is_closed()
873
+ True
874
+ """
875
+ if self.is_closed():
876
+ return self
877
+ try:
878
+ codomain_subset_closure = self._codomain_subset.closure()
879
+ except AttributeError:
880
+ return super().closure()
881
+ closure = ManifoldSubsetPullback(self._map, codomain_subset_closure,
882
+ inverse=self._inverse,
883
+ name=name, latex_name=latex_name)
884
+ closure.declare_superset(self)
885
+ return closure