Hi,
We have just released a new version of SageManifolds at
http://sagemanifolds.obspm.fr/With respect to previous version, a whole rewriting of the code has been performed, aiming at a better integration in Sage. In particular, the tensor on free modules stuff, described in
this post and on
this page has been included in this release to describe both (i) tensor fields on parallelizable domains and (ii) tensor on the tangent spaces. Sage Parent/Element scheme is now employed for Domain/Point, ScalarFieldAlgebra/ScalarField, TensorFieldModule/TensorField and TangentSpace/TangentVector. All the parents inherit from Sage's classes UniqueRepresentation and Parent (some class diagrams are depicted
here). Coercions between parents have also been implemented, as illustrated by the following 2-sphere example:
We first construct the S^2 manifold and cover it by a set of two charts:
sage: M = Manifold(2, 'S^2') # declaration as a 2-dimensional manifold
sage: U = M.open_domain('U') ; V = M.open_domain('V') # the complements of the North pole and South pole, respectively
sage: M.declare_union(U,V) # the union of U and V is M
sage: stereoN.<x,y> = U.chart() # stereographic coordinates from the North pole
sage: stereoS.<u,v> = V.chart() # stereographic coordinates from the South pole
sage: N_to_S = stereoN.transition_map(stereoS, (x/(x^2+y^2), y/(x^2+y^2)), intersection_name='W', restrictions1= x^2+y^2!=0, restrictions2= u^2+v^2!=0) # the transition map between the two charts
sage: S_to_N = N_to_S.inverse() # the inverse of the transition map is computed
sage: M.atlas() # the open set W below is the intersection of U and V
[chart (U, (x, y)), chart (V, (u, v)), chart (W, (x, y)), chart (W, (u, v))]
Points on S^2 have for parent domains on the manifolds; hence they can be constructed by the method __call__ applied to their parent, the argument being their coordinates in some chart:
sage: N = V((0,0), chart=stereoS, name='N') ; N # the North pole
point 'N' on 2-dimensional manifold 'S^2'
sage: S = U((0,0), chart=stereoN, name='S') ; S # the South pole
point 'S' on 2-dimensional manifold 'S^2'
sage: p = U((1,0), chart=stereoN, name='p') ; p # some point at the equator
point 'p' on 2-dimensional manifold 'S^2'
Let us consider a (smooth) scalar field on S^2, defined by its coordinate expression in the two charts:
sage: f = M.scalar_field({stereoN: atan(x^2+y^2), stereoS: pi/2-atan(u^2+v^2)}, name='f')
sage: f.view()
f: S^2 --> R
on U: (x, y) |--> arctan(x^2 + y^2)
on V: (u, v) |--> 1/2*pi - arctan(u^2 + v^2)
sage: f(N), f(p), f(S) # scalar fields map manifold points to real numbers
(1/2*pi, 1/4*pi, 0)
The parent of scalar fields is the commutative algebra C^oo(M):
sage: CM = f.parent() ; CM
algebra of scalar fields on the 2-dimensional manifold 'S^2'
sage: CM.category()
Category of commutative algebras over Symbolic Ring
sage: TestSuite(CM).run() # the commutative algebra test suite is passed
The set C^oo(U) of scalar fields defined on U is
sage: CU = U.scalar_field_algebra() ; CU
algebra of scalar fields on the open domain 'U' on the 2-dimensional manifold 'S^2'
There is a coercion from C^oo(M) to C^oo(U) but not in the reverse way:
sage: CU.has_coerce_map_from(CM)
True
sage: CM.has_coerce_map_from(CU)
False
Indeed, the coercion from C^oo(M) to C^oo(U) is nothing but the restriction to U:
sage: g = CU(f) ; g # f coerced to an element of C^oo(U)
scalar field on the open domain 'U' on the 2-dimensional manifold 'S^2'
sage: g.view()
U --> R
(x, y) |--> arctan(x^2 + y^2)
on W: (u, v) |--> 1/2*pi - arctan(u^2 + v^2)
sage: g == f.restrict(U)
True
The set X(M) of (smooth) vector fields on S^2 is a module over the algebra C^oo(M):
sage: XM = M.vector_field_module() ; XM
module X(S^2) of vector fields on the 2-dimensional manifold 'S^2'
sage: XM.category()
Category of modules over algebra of scalar fields on the 2-dimensional manifold 'S^2'
sage: XM.base_ring() is CM
True
sage: TestSuite(XM).run() # the module test suite is passed
X(M) is not a free module, for M=S^2 is not a parallelizable manifold (i.e. it does not admit any global vector frame):
sage: isinstance(XM, FiniteRankFreeModule)
False
sage: M.is_manifestly_parallelizable()
False
On the contrary, the set X(U) of vector fields on U is a free module:
sage: XU = U.vector_field_module() ; XU
free module X(U) of vector fields on the open domain 'U' on the 2-dimensional manifold 'S^2'
sage: XU.category()
Category of modules over algebra of scalar fields on the open domain 'U' on the 2-dimensional manifold 'S^2'
sage: XU.base_ring() is CU
True
sage: TestSuite(XU).run() # the module test suite is passed
Indeed, U admits a global vector frame: the coordinate frame (d/dx, d/dy):
sage: U.is_manifestly_parallelizable()
True
sage: U.frames() # list of frames defined on open subsets of U
[coordinate frame (U, (d/dx,d/dy)),
coordinate frame (W, (d/dx,d/dy)),
coordinate frame (W, (d/du,d/dv))]
sage: eN = stereoN.frame() ; eN # the vector frame associated with stereographic coordinates (x,y) from the North pole
coordinate frame (U, (d/dx,d/dy))
sage: eS = stereoS.frame() ; eS # similarly, we define the frame associated with stereographic coordinates from the South pole
coordinate frame (V, (d/du,d/dv))
There is a coercion from X(M) to X(U), which is the restriction of vector fields to U:
sage: XU.has_coerce_map_from(XM)
True
To illustrate it, let us consider a vector field on S^2, for instance the azimuthal rotation vector d/dphi:
sage: w = M.vector_field(name='w')
sage: w[eN,:] = [-y, x] # w is defined by its components with respect to the frame eN
sage: w.add_comp_by_continuation(eS, U.intersection(V), stereoS) # the components in the frame eS are deduced by analytic continuation from the domain common to both eN and eS
sage: w.view(eN)
w = -y d/dx + x d/dy
sage: w.view(eS)
w = -v d/du + u d/dv
sage: w(f) # vector fields act on scalar fields
scalar field 'w(f)' on the 2-dimensional manifold 'S^2'
sage: w.parent() is XM
True
Let us coerce w to X(U):
sage: wU = XU(w) ; wU
vector field 'w' on the open domain 'U' on the 2-dimensional manifold 'S^2'
sage: wU.view() # view in the default frame of U, which is eN
w = -y d/dx + x d/dy
sage: wU == w.restrict(U) # the coercion is nothing but the restriction to U
True
This type of coercion is extended to any tensor field module (XM being considered as the module of type-(1,0) tensor fields), for instance, type-(0,1) tensor fields (i.e. 1-forms):
sage: df = f.differential() ; df
1-form 'df' on the 2-dimensional manifold 'S^2'
sage: df.view(eN)
df = 2*x/(x^4 + 2*x^2*y^2 + y^4 + 1) dx + 2*y/(x^4 + 2*x^2*y^2 + y^4 + 1) dy
sage: df.view(eS)
df = -2*u/(u^4 + 2*u^2*v^2 + v^4 + 1) du - 2*v/(u^4 + 2*u^2*v^2 + v^4 + 1) dv
sage: df.parent()
module T^(0,1)(S^2) of type-(0,1) tensors fields on the 2-dimensional manifold 'S^2'
sage: T01M = M.tensor_field_module((0,1)) ; df.parent() is T01M
True
sage: T01M.category()
Category of modules over algebra of scalar fields on the 2-dimensional manifold 'S^2'
sage: TestSuite(T01M).run() # the module test suite is passed
sage: T01U = U.tensor_field_module((0,1)) ; T01U
free module T^(0,1)(U) of type-(0,1) tensors fields on the open domain 'U' on the 2-dimensional manifold 'S^2'
sage: T01U.has_coerce_map_from(T01M)
True
Another algebraic structure introduced in SageManifolds 0.5 is the tangent vector spaces at points on the manifold:
sage: Tp = p.tangent_space() ; Tp
tangent space at point 'p' on 2-dimensional manifold 'S^2'
sage: Tp.category()
Category of vector spaces over Symbolic Ring
sage: isinstance(Tp, FiniteRankFreeModule) # a finite-dimensional vector space is of course a free module of finite rank
True
sage: Tp.dim()
2
The value of a vector field at a given point is a vector in the tangent space:
sage: wp = w.at(p) ; wp
tangent vector w at point 'p' on 2-dimensional manifold 'S^2'
sage: wp.parent() is Tp
True
while the value of a 1-form is an element of the dual vector space:
sage: dfp = df.at(p) ; dfp
linear form df on the tangent space at point 'p' on 2-dimensional manifold 'S^2'
sage: dfp.parent() is Tp.dual()
True
The 2-sphere example is more detailed (in particular its Riemannian structure) in this
page.
Other changes in this release, which follow from discussion on this list, are
- All class attributes are now hidden (underscore prefix) and the corresponding accessor methods have been added (e.g. Tp.dim() returns Tp._rank)
- Only the classes Manifold, RealLine and FiniteRankFreeModule are now imported in the global name space of a Sage session. All constructions of objects not belonging to these classes are performed by specific method calls on other objects.
SageManifolds 0.5 is submitted to Sage trac in two parts:
- ticket
#15916: the pure algebraic part (tensors on free modules)
- ticket
#14865: the differential part (manifolds and tensor fields)
As usual, comments and suggestions are welcome, not speaking about help in the code development ! (future directions should involve graphical outputs, parallelization of tensor computations, curves and immersed submanifolds,
geodesics, integration)