Ticket #9650: trac9650_differential_forms_v2-reviewer.patch

File trac9650_differential_forms_v2-reviewer.patch, 57.2 KB (added by niles, 11 years ago)

corrected formatting for NotImplemented? methods

• doc/en/reference/index.rst

# HG changeset patch
# User Joris Vankerschaver <joris.vankerschaver@gmail.com>
# Date 1283673022 -7200
# Node ID 77cf8caa3554417432b47b0e674e0cd6df76edf5
# Parent  5b338f2e484f2065d3d30d47bc204d6e9ed13d12
#9650: Add support for differential forms

diff -r 5b338f2e484f -r 77cf8caa3554 doc/en/reference/index.rst
 a modfrm modabvar modmisc tensor history_and_license
• new file doc/en/reference/tensor.rst

diff -r 5b338f2e484f -r 77cf8caa3554 doc/en/reference/tensor.rst
 - Differential Forms ================== .. toctree:: :maxdepth: 2 sage/tensor/coordinate_patch sage/tensor/differential_forms sage/tensor/differential_form_element
• sage/all.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/all.py
 a from sage.ext.fast_callable  import fast_callable from sage.ext.fast_eval      import fast_float from sage.tensor.all     import * from copy import copy, deepcopy # The code executed here uses a large amount of Sage components
• new file sage/tensor/__init__.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/tensor/__init__.py
 - # This comment is here so the file is non-empty (so Mercurial will check it in).
• new file sage/tensor/all.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/tensor/all.py
 - from coordinate_patch import CoordinatePatch from differential_forms import DifferentialForms from differential_form_element import DifferentialForm, wedge
• new file sage/tensor/coordinate_patch.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/tensor/coordinate_patch.py
 - r""" Open subset of Euclidian space with coordinates. An open subset of Euclidian space with a specific set of coordinates.  This is the background on which differential forms can be defined. AUTHORS: - Joris Vankerschaver (2010-07-25) EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z :: sage: u, v = var('u, v') sage: S = CoordinatePatch((u, v)); S Open subset of R^2 with coordinates u, v TODO: - Add functionality for metric tensors """ #***************************************************************************** #    Copyright (C) 2010 Joris Vankerschaver # #  Distributed under the terms of the GNU General Public License (GPL) # #    This code is distributed in the hope that it will be useful, #    but WITHOUT ANY WARRANTY; without even the implied warranty of #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU #    General Public License for more details. # #  The full text of the GPL is available at: # #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.parent import Parent from sage.symbolic.ring import SR, var class CoordinatePatch(Parent): """ Construct a coordinate patch, i.e. an open subset of Euclidian space with a given set of coordinates. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: u, v = var('u, v') sage: T = CoordinatePatch((u, v)); T Open subset of R^2 with coordinates u, v sage: loads(T.dumps()) == T True In a future release, it will be possible to specify a metric tensor on a coordinate patch.  For now, providing any kind of metric raises an exception:: sage: x, y, z = var('x, y, z') sage: m = matrix(SR, 3) sage: S = CoordinatePatch((x, y, z), metric=m) Traceback (most recent call last): ... NotImplementedError: Metric geometry not supported yet. """ def __init__(self, coordinates, metric = None): """ An open subset of Euclidian space with a specific set of coordinates. See CoordinatePatch for details. INPUT:: - coordinates -- a set of symbolic variables that serve as coordinates on this space. - metric (default: None) -- a metric tensor on this coordinate patch.  Providing anything other than None is currently not defined. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z """ from sage.symbolic.ring import is_SymbolicVariable if not all(is_SymbolicVariable(c) for c in coordinates): raise TypeError, "%s is not a valid vector of coordinates." % \ coordinates self._coordinates = tuple(coordinates) dim = len(self._coordinates) if metric is not None: raise NotImplementedError, "Metric geometry not supported yet." def __cmp__(self, other): """ Compare self and other.  Return equality if and only if other has the same coordinates as self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: u, v = var('u, v') sage: T = CoordinatePatch((u, v)); T Open subset of R^2 with coordinates u, v sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: cmp(U, S) 0 sage: cmp(U, U) 0 sage: cmp(U, T) 1 """ return cmp(self._coordinates, other._coordinates) def coordinates(self): """ Return coordinates on this coordinate patch. OUTPUT: - list - a list of coordinates on this space. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: S.coordinates() (x, y, z) """ return self._coordinates def coordinate(self, i=0): """ Return the i^{th} coordinate on self INPUT: - i - integer (optional, default 0) EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: S.coordinate(0) x sage: S.coordinate(1) y sage: S.coordinate(2) z """ return self._coordinates[i] def dim(self): """ Return the dimension of this coordinate patch, i.e. the dimension of the Euclidian space of which this coordinate patch is an open subset. EXAMPLES:: sage: a, b, c, d, e = var('a, b, c, d, e') sage: U = CoordinatePatch((a, b, c, d, e)); U Open subset of R^5 with coordinates a, b, c, d, e sage: U.dim() 5 """ return len(self._coordinates) def _repr_(self): r""" Return string representation of this coordinate patch. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: S._repr_() 'Open subset of R^3 with coordinates x, y, z' sage: S.rename('coordinate patch'); S coordinate patch sage: S.rename(); S Open subset of R^3 with coordinates x, y, z """ return r"Open subset of R^%s with coordinates %s" % \ (self.dim(), ', '.join([x._latex_() for x in self._coordinates])) def _latex_(self): r""" Return latex representation of this coordinate patch. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: S = CoordinatePatch((x, y, z)); S Open subset of R^3 with coordinates x, y, z sage: latex(S) \mathbb{\RR}^3 sage: latex(S) == S._latex_() True """ return "\\mathbb{\RR}^%s" % self.dim()
• new file sage/tensor/differential_form_element.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/tensor/differential_form_element.py
 - r""" Elements of the algebra of differential forms. AUTHORS: - Joris Vankerschaver (2010-07-25) """ #***************************************************************************** #  Copyright (C) 2010 Joris Vankerschaver # #  Distributed under the terms of the GNU General Public License (GPL) # #    This code is distributed in the hope that it will be useful, #    but WITHOUT ANY WARRANTY; without even the implied warranty of #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU #    General Public License for more details. # #  The full text of the GPL is available at: # #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.symbolic.ring import SymbolicRing, SR from sage.rings.ring_element import RingElement from sage.algebras.algebra_element import AlgebraElement from sage.rings.integer import Integer from sage.combinat.permutation import Permutation def sort_subscript(subscript): """ A subscript is a range of integers.  This function sorts a subscript in the sense of arranging it in ascending order.  The return values are the sign of the subscript and the sorted subscript, where the sign is defined as follows: #. sign == 0 if two or more entries in the subscript were equal. #. sign == +1, -1 if a positive (resp. negative) permutation was used to sort the subscript. INPUT: - subscript -- a subscript, i.e. a range of not necessarily distinct integers OUTPUT: - Sign of the permutation used to arrange the subscript, where 0 means that the original subscript had two or more entries that were the same - Sorted subscript. EXAMPLES:: sage: from sage.tensor.differential_form_element import sort_subscript sage: sort_subscript((1, 3, 2)) (-1, (1, 2, 3)) sage: sort_subscript((1, 3)) (1, (1, 3)) sage: sort_subscript((4, 2, 7, 9, 8)) (1, (2, 4, 7, 8, 9)) """ if len(subscript) == 0: return 1, () sub_list = list(subscript) sub_list.sort() offsets = [subscript.index(x)+1 for x in sub_list] # Check that offsets is a true permutation of 1..n n = len(offsets) if sum(offsets) != n*(n+1)/2: sign = 0 else: sign = Permutation(offsets).signature() return sign, tuple(sub_list) class DifferentialFormFormatter: r""" This class contains all the functionality to print a differential form in a graphically pleasing way.  This class is called by the _latex_ and _repr_ methods of the DifferentialForm class. In a nutshell (see the documentation of DifferentialForm for more details), differential forms are represented internally as a dictionary, where the keys are tuples representing the non-zero components of the form and the values are the component functions.  The methods of this class create string and latex representations out of the specification of a subscript and a component function. EXAMPLES:: sage: from sage.tensor.differential_form_element import DifferentialFormFormatter sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: D = DifferentialFormFormatter(U) sage: D.repr((0, 2), sin(x*y)) 'sin(x*y)*dx/\\dz' sage: D.latex((0, 2), sin(x*y)) '\\sin\\left(x y\\right) d x \\wedge d z' sage: D.latex((1, 2), exp(z)) 'e^{z} d y \\wedge d z' """ def __init__(self, space): r""" Construct a differential form formatter.  See DifferentialFormFormatter for more information. INPUT: - space -- CoordinatePatch where the differential forms live. EXAMPLES:: sage: from sage.tensor.differential_form_element import DifferentialFormFormatter sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: D = DifferentialFormFormatter(U) sage: D.repr((0, 2), sin(x*y)) 'sin(x*y)*dx/\\dz' """ self._space = space def repr(self, comp, fun): r""" String representation of a primitive differential form, i.e. a function times a wedge product of d's of the coordinate functions. INPUT: - comp -- a subscript of a differential form. - fun -- the component function of this form. EXAMPLES:: sage: from sage.tensor.differential_form_element import DifferentialFormFormatter sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: D = DifferentialFormFormatter(U) sage: D.repr((0, 1), z^3) 'z^3*dx/\\dy' """ str = "/\\".join( \ [('d%s' % self._space.coordinate(c).__repr__()) for c in comp]) if fun == 1 and len(comp) > 0: # We have a non-trivial form whose component function is 1, # so we just return the formatted form part and ignore the 1. return str else: funstr = fun._repr_() if not self._is_atomic(funstr): funstr = '(' + funstr + ')' if len(str) > 0: return funstr + "*" + str else: return funstr def latex(self, comp, fun): r""" Latex representation of a primitive differential form, i.e. a function times a wedge product of d's of the coordinate functions. INPUT: - comp -- a subscript of a differential form. - fun -- the component function of this form. EXAMPLES:: sage: from sage.tensor.differential_form_element import DifferentialFormFormatter sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: D = DifferentialFormFormatter(U) sage: D.latex((0, 1), z^3) 'z^{3} d x \\wedge d y' """ from sage.misc.latex import latex str = " \\wedge ".join( \ [('d %s' % latex(self._space.coordinate(c))) for c in comp]) if fun == 1 and len(comp) > 0: return str else: funstr = latex(fun) if not self._is_atomic(funstr): funstr = '(' + funstr + ')' return funstr + " " + str def _is_atomic(self, str): r""" Helper function to check whether a given string expression is atomic. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: from sage.tensor.differential_form_element import DifferentialFormFormatter sage: D = DifferentialFormFormatter(U) sage: D._is_atomic('a + b') False sage: D._is_atomic('(a + b)') True """ level = 0 for n, c in enumerate(str): if c == '(': level += 1 elif c == ')': level -= 1 if c == '+' or c == '-': if level == 0 and n > 0: return False return True class DifferentialForm(AlgebraElement): r""" Differential form class. EXAMPLES: In order to instantiate differential forms of various degree, we begin by specifying the CoordinatePatch on which they live, as well as their parent DifferentialForms algebra. :: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: F = DifferentialForms(U) sage: form1 = DifferentialForm(F, 0, sin(x*y)); form1 sin(x*y) In the previous example, we created a zero-form from a given function. To create forms of higher degree, we can use the subscript operator access the various components:: sage: form2 = DifferentialForm(F, 1); form2 0 sage: form2[0] = 1 sage: form2[1] = exp(cos(x)) sage: form2[2] = 1/ln(y) sage: form2 1/log(y)*dz + dx + e^cos(x)*dy We may calculate the exterior derivative of a form, and observe that applying the exterior derivative twice always yields zero:: sage: dform = form1.diff(); dform y*cos(x*y)*dx + x*cos(x*y)*dy sage: dform.diff() 0 As can be seen from the previous example, the exterior derivative increases the degree of a form by one:: sage: form2.degree() 1 sage: form2.diff().degree() 2 The d function provides a convenient shorthand for applying the diff member function.  Since d appears in other areas of mathematics as well, this function is not imported in the global namespace automatically:: sage: from sage.tensor.differential_form_element import d sage: form2 1/log(y)*dz + dx + e^cos(x)*dy sage: d(form2) -(1/y)/log(y)^2*dy/\dz + -e^cos(x)*sin(x)*dx/\dy sage: form2.diff() -(1/y)/log(y)^2*dy/\dz + -e^cos(x)*sin(x)*dx/\dy sage: d(form1) == form1.diff() True The wedge product of two forms can be computed by means of the wedge member function:: sage: form1 = DifferentialForm(F, 2) sage: form1[0, 1] = exp(z); form1 e^z*dx/\dy sage: form2 = DifferentialForm(F, 1) sage: form2[2] = exp(-z) sage: form1.wedge(form2) dx/\dy/\dz For this member function, there exists again a procedural function which is completely equivalent:: sage: from sage.tensor.differential_form_element import wedge sage: form1.wedge(form2) dx/\dy/\dz sage: wedge(form1, form2) dx/\dy/\dz sage: form1.wedge(form2) == wedge(form1, form2) True NOTES: Differential forms are stored behind the screens as dictionaries, where the keys are the subscripts of the non-zero components, and the values are those components. For example, on a space with coordinates x, y, z, the form f = sin(x*y) dx /\\ dy + exp(z) dy /\\ dz would be represented as the dictionary {(0, 1): sin(x*y), (1, 2): exp(z)}. Most differential forms are ''sparse'' in the sense that most of their components are zero, so that this representation is more efficient than storing all of the components in a vector. """ def __init__(self, parent, degree, fun = None): r""" Construct a differential form. INPUT: - parent -- Parent algebra of differential forms. - degree -- Degree of the differential form. - fun (default: None) -- Initialize this differential form with the given function.  If the degree is not zero, this argument is silently ignored. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 0, sin(z)); f sin(z) """ from sage.tensor.differential_forms import DifferentialForms if not isinstance(parent, DifferentialForms): raise TypeError, "Parent not an algebra of differential forms." RingElement.__init__(self, parent) self._degree = degree self._components = {} if degree == 0 and fun is not None: self.__setitem__([], fun) def __getitem__(self, subscript): r""" Return a given component of the differential form. INPUT: - subscript: subscript of the component.  Must be an integer or a list of integers. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 0, sin(x*y)); f sin(x*y) sage: f[()] sin(x*y) sage: df = f.diff(); df y*cos(x*y)*dx + x*cos(x*y)*dy sage: df[0] y*cos(x*y) sage: df[1] x*cos(x*y) sage: df[2] 0 """ if isinstance(subscript, (Integer, int)): subscript = (subscript, ) else: subscript = tuple(subscript) dim = self.parent().base_space().dim() if any([s >= dim for s in subscript]): raise ValueError, "Index out of bounds." if len(subscript) != self._degree: raise TypeError, "%s is not a subscript of degree %s" %\ (subscript, self._degree) sign, subscript = sort_subscript(subscript) if subscript in self._components: return sign*self._components[subscript] else: return 0 def __setitem__(self, subscript, fun): r""" Modify a given component of the differential form. INPUT: - subscript: subscript of the component.  Must be an integer or a list of integers. EXAMPLES:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 2) sage: f[1, 2] = x; f x*dy/\dz """ if isinstance(subscript, (Integer, int)): subscript = (subscript, ) else: subscript = tuple(subscript) dim = self.parent().base_space().dim() if any([s >= dim for s in subscript]): raise ValueError, "Index out of bounds." if len(subscript) != self._degree: raise TypeError, "%s is not a subscript of degree %s" %\ (subscript, self._degree) sign, subscript = sort_subscript(subscript) self._components[subscript] = sign*SR(fun) def is_zero(self): r""" Return True if self is the zero form. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1); f 0 sage: f.is_zero() True sage: f[1] = 1 sage: f.is_zero() False sage: f.diff() 0 sage: f.diff().is_zero() True """ self._cleanup() return len(self._components) == 0 def degree(self): r""" Return the degree of self. EXAMPLES:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 2) sage: f[1, 2] = x; f x*dy/\dz sage: f.degree() 2 The exterior differential increases the degree of forms by one:: sage: g = f.diff(); g dx/\dy/\dz sage: g.degree() 3 """ return self._degree def __eq__(self, other): r""" Test whether two differential forms are equal. EXAMPLES:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 2) sage: f[1,2] = x; f x*dy/\dz sage: f == f True sage: g = DifferentialForm(F, 3) sage: g[0, 1, 2] = 1; g dx/\dy/\dz sage: f == g False sage: f.diff() == g True """ if type(other) == type(self): return self.__dict__ == other.__dict__ return False #def __ne__(self, other): #    return not self.__eq__(other) def _neg_(self): r""" Return the negative of self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[0] = y sage: f[1] = -x sage: f y*dx + -x*dy sage: -f -y*dx + x*dy sage: -f == f._neg_() True """ neg = DifferentialForm(self.parent(), self._degree) for comp in self._components: neg._components[comp] = -self._components[comp] return neg def _add_(self, other): r""" Add self and other EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: g = DifferentialForm(F, 1) sage: f[0] = exp(x); f e^x*dx sage: g[1] = sin(y); g sin(y)*dy sage: f + g e^x*dx + sin(y)*dy sage: f + g == f._add_(g) True Forms must have the same degree to be added:: sage: h = DifferentialForm(F, 2) sage: h[1, 2] = x; h x*dy/\dz sage: f + h Traceback (most recent call last): ... TypeError: Cannot add forms of degree 1 and 2 """ if self.is_zero(): return other if other.is_zero(): return self if self._degree != other._degree: raise TypeError, \ "Cannot add forms of degree %s and %s" % \ (self._degree, other._degree) sumform = DifferentialForm(self.parent(), self._degree) sumform._components = self._components.copy() for comp, fun in other._components.items(): sumform[comp] += fun sumform._cleanup() return sumform def _sub_(self, other): r""" Subtract other from self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: g = DifferentialForm(F, 1) sage: f[0] = exp(x); f e^x*dx sage: g[1] = sin(y); g sin(y)*dy sage: f - g e^x*dx + -sin(y)*dy sage: f - g == f._sub_(g) True Forms must have the same degree to be subtracted:: sage: h = DifferentialForm(F, 2) sage: h[1, 2] = x; h x*dy/\dz sage: f - h Traceback (most recent call last): ... TypeError: Cannot add forms of degree 1 and 2 """ return self._add_(-other) def _cleanup(self): r""" Helper function to clean up self, i.e. to remove any zero components from the dictionary of components. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[0] = 0 sage: f[1] = 1 sage: f[2] = 0 sage: f._dump_all() {(2,): 0, (0,): 0, (1,): 1} sage: f._cleanup() sage: f._dump_all() {(1,): 1} """ zeros = [] for comp in self._components: if self._components[comp] == 0: zeros.append(comp) for comp in zeros: del self._components[comp] def _dump_all(self): r""" Helper function to dump the internal dictionary of form components. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[1] = exp(cos(x)) sage: f[2] = sin(ln(y)) sage: f sin(log(y))*dz + e^cos(x)*dy sage: f._dump_all() {(2,): sin(log(y)), (1,): e^cos(x)} sage: g = DifferentialForm(F, 2) sage: g[1, 2] = x+y+z sage: g (x + y + z)*dy/\dz sage: g._dump_all() {(1, 2): x + y + z} """ print self._components def diff(self): r""" Compute the exterior differential of self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 0, sin(x*y)); f sin(x*y) sage: f.diff() y*cos(x*y)*dx + x*cos(x*y)*dy sage: g = DifferentialForm(F, 1) sage: g[0] = y/2 sage: g[1] = -x/2 sage: g 1/2*y*dx + -1/2*x*dy sage: g.diff() -1*dx/\dy sage: h = DifferentialForm(F, 2) sage: h[0, 1] = exp(z) sage: h.diff() e^z*dx/\dy/\dz The square of the exterior differential operator is identically zero:: sage: f sin(x*y) sage: f.diff() y*cos(x*y)*dx + x*cos(x*y)*dy sage: f.diff().diff() 0 sage: g.diff().diff() 0 The exterior differential operator is a derivation of degree one on the space of differential forms.  In this example we import the operator d() as a short-hand for having to call the diff() member function. :: sage: from sage.tensor.differential_form_element import d sage: d(f) y*cos(x*y)*dx + x*cos(x*y)*dy sage: d(f).wedge(g) + f.wedge(d(g)) (-x*y*cos(x*y) - sin(x*y))*dx/\dy sage: d(f.wedge(g)) (-x*y*cos(x*y) - sin(x*y))*dx/\dy sage: d(f.wedge(g)) == d(f).wedge(g) + f.wedge(d(g)) True """ diff_form = DifferentialForm(self.parent(), self._degree + 1) for comp in self._components: fun = self._components[comp] for n, coord in enumerate(self.parent().base_space().coordinates()): diff_form[(n, ) + comp] += fun.differentiate(coord) diff_form._cleanup() return diff_form def derivative(self, *args, **kwargs): r""" Compute the exterior derivative of self.  This is the same as calling the diff member function. EXAMPLES:: sage: x, y = var('x, y') sage: U = CoordinatePatch((x, y)) sage: F = DifferentialForms(U) sage: q = DifferentialForm(F, 1) sage: q[0] = -y/2 sage: q[1] =  x/2 sage: q.diff() dx/\dy sage: q.derivative() dx/\dy Invoking diff on a differential form has the same effect as calling this member function:: sage: diff(q) dx/\dy sage: diff(q) == q.derivative() True When additional arguments are supplied to diff, an error is raised, since only the exterior derivative has intrinsic meaning while derivatives with respect to the coordinate variables (in whichever way) are coordinate dependent, and hence not intrinsic. :: sage: diff(q, x) Traceback (most recent call last): ... ValueError: Differentiation of a form does not take any arguments. """ if len(args) > 0 or len(kwargs) > 0: raise ValueError, "Differentiation of a form does not take any arguments." return self.diff() def wedge(self, other): r""" Returns the wedge product of self and other. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[0] = x^2 sage: f[1] = y sage: f x^2*dx + y*dy sage: g = DifferentialForm(F, 1) sage: g[2] = z^3 sage: g z^3*dz sage: f.wedge(g) y*z^3*dy/\dz + x^2*z^3*dx/\dz The wedge product is graded commutative:: sage: f.wedge(g) y*z^3*dy/\dz + x^2*z^3*dx/\dz sage: g.wedge(f) -y*z^3*dy/\dz + -x^2*z^3*dx/\dz sage: f.wedge(f) 0 When the wedge product of forms belonging to different algebras is computed, an error is raised:: sage: x, y, p, q = var('x, y, p, q') sage: F = DifferentialForms(CoordinatePatch((x, y))) sage: G = DifferentialForms(CoordinatePatch((p, q))) sage: f = DifferentialForm(F, 0, 1); f 1 sage: g = DifferentialForm(G, 0, x); g x sage: f.parent() Algebra of differential forms in the variables x, y sage: g.parent() Algebra of differential forms in the variables p, q sage: f.wedge(g) Traceback (most recent call last): ... TypeError: unsupported operand parents for wedge: 'Algebra of differential forms in the variables x, y' and  'Algebra of differential forms in the variables p, q' """ if self.parent() != other.parent(): raise TypeError, "unsupported operand parents for wedge: " +\ "\'%s\' and  \'%s\'" % (self.parent(), other.parent()) output = DifferentialForm(self.parent(), self._degree + other._degree) if self._degree + other._degree > self.parent().ngens(): return output for lcomp, lfun in self._components.items(): for rcomp, rfun in other._components.items(): output[lcomp + rcomp] += lfun*rfun output._cleanup() return output def _mul_(self, other): r""" Multiply self and other.  This is identical to the wedge operator. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = F.gen(0); f dx sage: g = F.gen(1); g dy sage: f*g dx/\dy sage: f.wedge(g) dx/\dy sage: f*g == f.wedge(g) True sage: f*g == f._mul_(g) True """ return self.wedge(other) def _latex_(self): r""" Return a latex representation of self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[1] = exp(z); f e^z*dy sage: latex(f) e^{z} d y sage: g = f.diff(); g -e^z*dy/\dz sage: latex(g) -e^{z} d y \wedge d z sage: latex(g) == g._latex_() True """ if len(self._components) == 0: return '0' format = DifferentialFormFormatter(self.parent().base_space()) output = [format.latex(comp, fun) \ for (comp, fun) in self._components.items()] return ' + '.join(output) def _repr_(self): r""" Return string representation of self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[1] = exp(z); f e^z*dy sage: print f e^z*dy sage: f._repr_() 'e^z*dy' """ if len(self._components) == 0: return '0' format = DifferentialFormFormatter(self.parent().base_space()) output = [format.repr(comp, fun) \ for (comp, fun) in self._components.items()] return ' + '.join(output) # Unsupported methods def abs(self): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.abs() Traceback (most recent call last): ... NotImplementedError: Absolute value not defined for differential forms. """ raise NotImplementedError, "Absolute value not defined for differential forms." def leading_coefficient(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.leading_coefficient() Traceback (most recent call last): ... NotImplementedError: leading_coefficient not defined for differential forms. """ raise NotImplementedError, "leading_coefficient not defined for differential forms." def leading_item(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.leading_item() Traceback (most recent call last): ... NotImplementedError: leading_item not defined for differential forms. """ raise NotImplementedError, "leading_item not defined for differential forms." def leading_monomial(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.leading_monomial() Traceback (most recent call last): ... NotImplementedError: leading_monomial not defined for differential forms. """ raise NotImplementedError, "leading_monomial not defined for differential forms." def leading_support(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.leading_support() Traceback (most recent call last): ... NotImplementedError: leading_support not defined for differential forms. """ raise NotImplementedError, "leading_support not defined for differential forms." def leading_term(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.leading_term() Traceback (most recent call last): ... NotImplementedError: leading_term not defined for differential forms. """ raise NotImplementedError, "leading_term not defined for differential forms." def trailing_coefficient(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.trailing_coefficient() Traceback (most recent call last): ... NotImplementedError: trailing_coefficient not defined for differential forms. """ raise NotImplementedError, "trailing_coefficient not defined for differential forms." def trailing_item(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.trailing_item() Traceback (most recent call last): ... NotImplementedError: leading_coefficient not defined for differential forms. """ raise NotImplementedError, "leading_coefficient not defined for differential forms." def trailing_monomial(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.trailing_monomial() Traceback (most recent call last): ... NotImplementedError: trailing_monomial not defined for differential forms. """ raise NotImplementedError, "trailing_monomial not defined for differential forms." def trailing_support(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.trailing_support() Traceback (most recent call last): ... NotImplementedError: trailing_support not defined for differential forms. """ raise NotImplementedError, "trailing_support not defined for differential forms." def trailing_term(self, cmp=None): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.trailing_term() Traceback (most recent call last): ... NotImplementedError: trailing_term not defined for differential forms. """ raise NotImplementedError, "trailing_term not defined for differential forms." def map_coefficients(self, f): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.map_coefficients(lambda x: x) Traceback (most recent call last): ... NotImplementedError: map_coefficients not defined for differential forms. """ raise NotImplementedError, "map_coefficients not defined for differential forms." def map_item(self, f): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.map_item(lambda x: x) Traceback (most recent call last): ... NotImplementedError: map_item not defined for differential forms. """ raise NotImplementedError, "map_item not defined for differential forms." def map_support(self, f): """ Method not defined for differential forms. EXAMPLES:: sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f.map_support(lambda x: x) Traceback (most recent call last): ... NotImplementedError: map_support not defined for differential forms. """ raise NotImplementedError, "map_support not defined for differential forms." def d(form): r""" Returns the exterior derivative of a given form, i.e. calls the diff() member function. EXAMPLES:: sage: from sage.tensor.differential_form_element import d sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[2] = cos(x); f cos(x)*dz sage: d(f) -sin(x)*dx/\dz sage: f.diff() -sin(x)*dx/\dz sage: d(f) == f.diff() True """ return form.diff() def wedge(left, right): r""" Computes the wedge product of two forms, i.e. calls the wedge() member function. EXAMPLES:: sage: from sage.tensor.differential_form_element import wedge sage: x, y, z = var('x, y, z') sage: F = DifferentialForms() sage: f = DifferentialForm(F, 1) sage: f[2] = cos(x); f cos(x)*dz sage: g = DifferentialForm(F, 1) sage: g[1] = sin(y); g sin(y)*dy sage: wedge(f, g) -sin(y)*cos(x)*dy/\dz sage: f.wedge(g) -sin(y)*cos(x)*dy/\dz sage: wedge(f, g) == f.wedge(g) True """ return left.wedge(right)
• new file sage/tensor/differential_forms.py

diff -r 5b338f2e484f -r 77cf8caa3554 sage/tensor/differential_forms.py
 - r""" Algebra of differential forms. Algebra of differential forms defined on a CoordinatePatch (an open subset of Euclidian space, see CoordinatePatch for details). AUTHORS: - Joris Vankerschaver (2010-05-26) TODO: - Allow for forms with values in a vector space - Incorporate Kahler differentials REFERENCES: - R. Abraham, J. E. Marsden, and T. S. Ratiu: Manifolds, tensor analysis, and applications.  Springer-Verlag 1988, texts in Applied Mathematical Sciences, volume 75, 2nd edition. - http://en.wikipedia.org/wiki/Differential_form """ #***************************************************************************** #    Copyright (C) 2010 Joris Vankerschaver (joris.vankerschaver@gmail.com) # #  Distributed under the terms of the GNU General Public License (GPL) # #    This code is distributed in the hope that it will be useful, #    but WITHOUT ANY WARRANTY; without even the implied warranty of #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU #    General Public License for more details. # #  The full text of the GPL is available at: # #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.rings.ring import Algebra from sage.tensor.coordinate_patch import CoordinatePatch from sage.tensor.differential_form_element import DifferentialForm from sage.symbolic.ring import SR, var class DifferentialForms(Algebra): """ The algebra of all differential forms on an open subset of Euclidian space of arbitrary dimension. EXAMPLES: To define an algebra of differential forms, first create a coordinate patch:: sage: p, q = var('p, q') sage: U = CoordinatePatch((p, q)); U Open subset of R^2 with coordinates p, q sage: F = DifferentialForms(U); F Algebra of differential forms in the variables p, q If no coordinate patch is supplied, a default one (using the variables x, y, z) will be used:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z """ Element = DifferentialForm def __init__(self, coordinate_patch = None): """ Construct the algebra of differential forms on a given coordinate patch. See DifferentialForms for details. INPUT:: - coordinate_patch -- Coordinate patch where the algebra lives. If no coordinate patch is given, a default coordinate patch with coordinates (x, y, z) is used. EXAMPLES:: sage: p, q = var('p, q') sage: U = CoordinatePatch((p, q)); U Open subset of R^2 with coordinates p, q sage: F = DifferentialForms(U); F Algebra of differential forms in the variables p, q """ from sage.categories.graded_algebras_with_basis \ import GradedAlgebrasWithBasis from sage.structure.parent_gens import ParentWithGens if not coordinate_patch: x, y, z = var('x, y, z') coordinate_patch = CoordinatePatch((x, y, z)) if not isinstance(coordinate_patch, CoordinatePatch): raise TypeError, \ "%s not a valid Coordinate Patch" % coordinate_patch self._patch = coordinate_patch ParentWithGens.__init__(self, SR, \ category = GradedAlgebrasWithBasis(SR)) def __cmp__(self, other): """ Compare self with other. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: p, q = var('p, q') sage: V = CoordinatePatch((p, q)); V Open subset of R^2 with coordinates p, q sage: G = DifferentialForms(V); G Algebra of differential forms in the variables p, q sage: H = DifferentialForms(U); H Algebra of differential forms in the variables x, y, z sage: cmp(F, G) 1 sage: cmp(F, H) 0 """ if type(other) == type(self): return cmp(self._patch, other._patch) else: return -1 def ngens(self): """ Return the number of generators of this algebra. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F.ngens() 3 """ return len(self._patch.coordinates()) def gen(self, i=0): """ Return the i^{th} generator of self.  This is a one-form, more precisely the exterior derivative of the i-th coordinate. INPUT: - i - integer (optional, default 0) EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F.gen(0) dx sage: F.gen(1) dy sage: F.gen(2) dz """ form = DifferentialForm(self, 0, self._patch.coordinate(i)) return form.diff() def gens(self): """ Return a list of the generators of self. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F.gens() (dx, dy, dz) """ return tuple(self.gen(n) for n in xrange(0, self._patch.dim())) def base_space(self): """ Return the coordinate patch on which this algebra is defined. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F.base_space() Open subset of R^3 with coordinates x, y, z """ return self._patch def _element_constructor_(self, fun): """ Coerce a given function (element of the symbolic ring) into a differential form of degree zero. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F(sin(x*y))    # indirect doctest sin(x*y) """ fun = SR(fun) if fun not in self: raise ValueError, \ "Function not an element of this algebra of differential forms." return DifferentialForm(self, 0, fun) def __contains__(self, element): """ Check if a given element belongs to this algebra of differential forms. EXAMPLES:: sage: x, y, p, q = var('x, y, p, q') sage: U = CoordinatePatch((x, y)); U Open subset of R^2 with coordinates x, y sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y sage: x in F True sage: sin(y) in F True sage: p in F False sage: cos(q) in F False """ parent = None try: parent = element.parent() except AttributeError: pass if parent == self: return True if parent == SR: for coordinate in element.variables(): if coordinate not in self._patch.coordinates(): return False return True return False def _coerce_map_from_(self, S): """ Only the symbolic ring coerces into the algebra of differential forms. EXAMPLES:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: F._coerce_map_from_(SR) True sage: F._coerce_map_from_(F) True sage: F._coerce_map_from_(CC) False sage: F._coerce_map_from_(RR) False """ return S is SR or S is self def _repr_(self): r""" String representation of this algebra of differential forms. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: F._repr_() 'Algebra of differential forms in the variables x, y, z' """ from string import join return "Algebra of differential forms in the variables " + \ ', '.join([str(var) for var in self._patch.coordinates()]) def _latex_(self): r""" Latex representation of this algebra of differential forms. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)); U Open subset of R^3 with coordinates x, y, z sage: F = DifferentialForms(U); F Algebra of differential forms in the variables x, y, z sage: latex(F) \Omega^\ast(\mathbb{\RR}^3) sage: latex(F) == F._latex_() True """ return "\\Omega^\\ast(\mathbb{\\RR}^%s)" % self._patch.dim()
• setup.py

diff -r 5b338f2e484f -r 77cf8caa3554 setup.py
 a 'sage.server.trac', 'sage.structure', 'sage.structure.proof' 'sage.structure.proof', 'sage.tensor' ], scripts = [],