@@ -2786,28 +2786,33 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame,
27862786 for sdom in self ._supersets :
27872787 sdom ._frame_changes [(frame2 , frame1 )] = change_of_frame .inverse ()
27882788
2789- def vector_frame (self , symbol = None , latex_symbol = None , dest_map = None ,
2790- from_frame = None , indices = None , latex_indices = None ,
2791- symbol_dual = None , latex_symbol_dual = None ):
2789+ def vector_frame (self , * args , ** kwargs ):
27922790 r"""
27932791 Define a vector frame on ``self``.
27942792
27952793 A *vector frame* is a field on the manifold that provides, at each
27962794 point `p` of the manifold, a vector basis of the tangent space at `p`
27972795 (or at `\Phi(p)` when ``dest_map`` is not ``None``, see below).
27982796
2797+ The vector frame can be defined from a set of `n` linearly independent
2798+ vector fields, `n` being the dimension of ``self``.
2799+
27992800 .. SEEALSO::
28002801
28012802 :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`
28022803 for complete documentation.
28032804
28042805 INPUT:
28052806
2806- - ``symbol`` -- (default: ``None``) either a string, to be used as a
2807+ - ``symbol`` -- either a string, to be used as a
28072808 common base for the symbols of the vector fields constituting the
28082809 vector frame, or a list/tuple of strings, representing the individual
2809- symbols of the vector fields; can be ``None`` only if ``from_frame``
2810+ symbols of the vector fields; can be omitted only if ``from_frame``
28102811 is not ``None`` (see below)
2812+ - ``vector_fields`` -- tuple or list of `n` linearly independent vector
2813+ fields on the manifold ``self`` (`n` being the dimension of ``self``)
2814+ defining the vector frame; can be omitted if the vector frame is
2815+ created from scratch or if ``from_frame`` is not ``None``
28112816 - ``latex_symbol`` -- (default: ``None``) either a string, to be used
28122817 as a common base for the LaTeX symbols of the vector fields
28132818 constituting the vector frame, or a list/tuple of strings,
@@ -2818,8 +2823,8 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None,
28182823 destination map `\Phi:\ U \rightarrow M`, where `U` is ``self`` and
28192824 `M` is a differentiable manifold; for each `p\in U`, the vector
28202825 frame evaluated at `p` is a basis of the tangent space
2821- `T_{\Phi(p)}M`; if ``dest_map`` is ``None``, the identity is assumed
2822- (case of a vector frame *on* `U`)
2826+ `T_{\Phi(p)}M`; if ``dest_map`` is ``None``, the identity map is
2827+ assumed (case of a vector frame *on* `U`)
28232828 - ``from_frame`` -- (default: ``None``) vector frame `\tilde{e}`
28242829 on the codomain `M` of the destination map `\Phi`; the returned
28252830 frame `e` is then such that for all `p \in U`,
@@ -2845,14 +2850,72 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None,
28452850
28462851 EXAMPLES:
28472852
2848- Setting a vector frame on a 3-dimensional manifold::
2853+ Defining a vector frame from two linearly independent vector
2854+ fields on a 2-dimensional manifold::
28492855
2850- sage: M = Manifold(3, 'M')
2851- sage: X.<x,y,z> = M.chart()
2852- sage: e = M.vector_frame('e'); e
2853- Vector frame (M, (e_0,e_1,e_2))
2854- sage: e[0]
2855- Vector field e_0 on the 3-dimensional differentiable manifold M
2856+ sage: M = Manifold(2, 'M')
2857+ sage: X.<x,y> = M.chart()
2858+ sage: e0 = M.vector_field(1+x^2, 1+y^2)
2859+ sage: e1 = M.vector_field(2, -x*y)
2860+ sage: e = M.vector_frame('e', (e0, e1)); e
2861+ Vector frame (M, (e_0,e_1))
2862+ sage: e[0].display()
2863+ e_0 = (x^2 + 1) d/dx + (y^2 + 1) d/dy
2864+ sage: e[1].display()
2865+ e_1 = 2 d/dx - x*y d/dy
2866+ sage: (e[0], e[1]) == (e0, e1)
2867+ True
2868+
2869+ If the vector fields are not linearly independent, an error is
2870+ raised::
2871+
2872+ sage: z = M.vector_frame('z', (e0, -e0))
2873+ Traceback (most recent call last):
2874+ ...
2875+ ValueError: the provided vector fields are not linearly
2876+ independent
2877+
2878+ Another example, involving a pair vector fields along a curve::
2879+
2880+ sage: R.<t> = RealLine()
2881+ sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
2882+ sage: I = c.domain(); I
2883+ Real interval (0, 2*pi)
2884+ sage: v = c.tangent_vector_field()
2885+ sage: v.display()
2886+ c' = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy
2887+ sage: w = I.vector_field(1-2*cos(t)^2, cos(t), dest_map=c)
2888+ sage: u = I.vector_frame('u', (v, w))
2889+ sage: u[0].display()
2890+ u_0 = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy
2891+ sage: u[1].display()
2892+ u_1 = (-2*cos(t)^2 + 1) d/dx + cos(t) d/dy
2893+ sage: (u[0], u[1]) == (v, w)
2894+ True
2895+
2896+ It is also possible to create a vector frame from scratch, without
2897+ connecting it to previously defined vector frames or vector fields
2898+ (this can still be performed later via the method
2899+ :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.set_change_of_frame`)::
2900+
2901+ sage: f = M.vector_frame('f'); f
2902+ Vector frame (M, (f_0,f_1))
2903+ sage: f[0]
2904+ Vector field f_0 on the 2-dimensional differentiable manifold M
2905+
2906+ Thanks to the keywords ``dest_map`` and ``from_frame``, one can also
2907+ define a vector frame from one prexisting on another manifold, via a
2908+ differentiable map (here provided by the curve ``c``)::
2909+
2910+ sage: fc = I.vector_frame(dest_map=c, from_frame=f); fc
2911+ Vector frame ((0, 2*pi), (f_0,f_1)) with values on the
2912+ 2-dimensional differentiable manifold M
2913+ sage: fc[0]
2914+ Vector field f_0 along the Real interval (0, 2*pi) with values on
2915+ the 2-dimensional differentiable manifold M
2916+
2917+ Note that the symbol for ``fc``, namely `f`, is inherited from ``f``,
2918+ the original vector frame.
28562919
28572920 .. SEEALSO::
28582921
@@ -2862,12 +2925,53 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None,
28622925
28632926 """
28642927 from sage .manifolds .differentiable .vectorframe import VectorFrame
2865- return VectorFrame (self .vector_field_module (dest_map = dest_map ,
2928+ # Input processing
2929+ symbol = None
2930+ vector_fields = None
2931+ n_args = len (args )
2932+ if n_args >= 1 :
2933+ symbol = args [0 ]
2934+ if n_args == 2 :
2935+ vector_fields = args [1 ]
2936+ elif n_args > 2 :
2937+ raise TypeError ("vector_frame() takes at most two positional "
2938+ "arguments" )
2939+ latex_symbol = kwargs .pop ('latex_symbol' , None )
2940+ dest_map = kwargs .pop ('dest_map' , None )
2941+ from_frame = kwargs .pop ('from_frame' , None )
2942+ indices = kwargs .pop ('indices' , None )
2943+ latex_indices = kwargs .pop ('latex_indices' , None )
2944+ symbol_dual = kwargs .pop ('symbol_dual' , None )
2945+ latex_symbol_dual = kwargs .pop ('latex_symbol_dual' , None )
2946+ #
2947+ if vector_fields :
2948+ dest_map0 = vector_fields [0 ].parent ().destination_map ()
2949+ if dest_map and dest_map is not dest_map0 :
2950+ raise ValueError ("incompatible values of destination maps" )
2951+ dest_map = dest_map0
2952+ resu = VectorFrame (self .vector_field_module (dest_map = dest_map ,
28662953 force_free = True ),
28672954 symbol = symbol , latex_symbol = latex_symbol ,
28682955 from_frame = from_frame , indices = indices ,
28692956 latex_indices = latex_indices , symbol_dual = symbol_dual ,
28702957 latex_symbol_dual = latex_symbol_dual )
2958+ if vector_fields :
2959+ linked = False
2960+ try :
2961+ resu ._init_from_family (vector_fields )
2962+ except ArithmeticError as err :
2963+ linked = str (err ) in ["non-invertible matrix" ,
2964+ "input matrix must be nonsingular" ]
2965+ if linked :
2966+ raise ValueError ("the provided vector fields are not "
2967+ "linearly independent" )
2968+ # Adding the newly generated changes of frame to the
2969+ # dictionary _frame_changes of self and its supersets:
2970+ for frame_pair , chge in resu ._fmodule ._basis_changes .items ():
2971+ if resu in frame_pair :
2972+ for sdom in self ._supersets :
2973+ sdom ._frame_changes [frame_pair ] = chge
2974+ return resu
28712975
28722976 def _set_covering_frame (self , frame ):
28732977 r"""
0 commit comments