Some comments: By not hiding attributes (not using underscores like self._manifold) you implement a mutable interface, essentially inviting users to change them. This of course will generally not work (e.g. reach into ZeroScalarField and making it non-zero). It also prevents you from ever using caching. In Sage, attributes are generally hidden (leading underscore convention) and accessor functions ensure immutabliity. One could also use read-only attributes but that is generally not done in Sage.
Having an extra ScalarField -> ZeroScalarField element subclass unnecessarily duplicates information about the value in the type. It makes the implementation awkward in that you always have to check if the result of operations is not zero so you don't accidentally construct a zero ScalarField. If its important to find out quickly if a field is zero or not just cache .is_zero() On Wednesday, May 28, 2014 2:44:58 PM UTC+1, Eric Gourgoulhon wrote: > > Dear Andrew (and Simon), > > I had exactly the same questions as yours (!) when trying to implement > algebraic structures related to fields on manifolds, for the SageManifolds > project. After reading the thematic tutorial by Simon and discussing with > Nicolas Thiery and other Sage experts in Paris, I came up with the > following solution. I am showing it here, not only to provide some concrete > example (maybe not a good one!) but to get comments from experts, before > going further in the actual implementation. > > Let us take the example of the set C^oo(U) of smooth real-valued functions > (scalar fields) U --> *R*, where U is some open subset of a > differentiable manifold M. This set is a commutative algebra over *R*. > Therefore, to represent it in Sage, we declare > > class ScalarFieldAlgebra(UniqueRepresentation, Parent): > > Element = ScalarField > > def __init__(self, domain): > Parent.__init__(self, base=SR, category=CommutativeAlgebras(SR)) > self.domain = domain > self._populate_coercion_lists_() > > > In the constructor, domain represents the open set U. Note that the field > *R* (over which the algebra is based) is "represented" by the symbolic > ring SR. > Then the class ScalarFieldAlgebra is equipped with the methods > _element_constructor_, _an_element_ and _coerce_map_from_, defined as > follows: > > def _element_constructor_(self, coord_expression=None, name=None, > latex_name=None): > if coord_expression == 0: > return ZeroScalarField(self.domain) > if isinstance(coord_expression, ScalarField): > if self.domain.is_subdomain(coord_expression.domain): > # restriction of the scalar field to self.domain: > sexpress = {} > for chart, funct in coord_expression.express.items(): > for schart in self.domain._atlas: > if schart in chart.subcharts: > sexpress[schart] = funct.expr() > resu = self.element_class(self.domain, > coord_expression=sexpress, name= > name, > latex_name=latex_name) > else: > raise TypeError("Cannot coerce the " + str( > coord_expression) + > "to a scalar field on the " + str(self. > domain)) > else: > resu = self.element_class(self.domain, > coord_expression=coord_expression, > name=name, latex_name=latex_name) > return resu > > def _an_element_(self): > return self.element_class(self.domain, coord_expression=2) > > > def _coerce_map_from_(self, other): > r""" > Determine whether coercion to self exists from other parent > """ > if other is SR: > return True # coercion from the base ring (multiplication by > the > # algebra unit, i.e. self.one()) > elif other is ZZ: > return True # important to define self(1) (for self.one()) > elif other is QQ: > return True > elif isinstance(other, ScalarFieldAlgebra): > return self.domain.is_subdomain(other.domain) > else: > return False > > > The elements, i.e. the smooth functions U --> *R,* are implemented as > follows: > > class ScalarField(CommutativeAlgebraElement): > def __init__(self, domain, coord_expression=None, name=None, > latex_name=None): > CommutativeAlgebraElement.__init__(self, domain. > scalar_field_algebra()) > self.manifold = domain.manifold > self.domain = domain > self.tensor_type = (0,0) > self.name = name > if latex_name is None: > self.latex_name = self.name > else: > self.latex_name = latex_name > self.express = {} > if coord_expression is not None: > if isinstance(coord_expression, FunctionChart): > self.express[coord_expression.chart] = coord_expression > elif isinstance(coord_expression, dict): > for chart, expression in coord_expression.items(): > if isinstance(expression, FunctionChart): > self.express[chart] = expression > else: > self.express[chart] = FunctionChart(chart,expression > ) > elif coord_expression == 0: > for chart in self.domain.</spa > ... -- You received this message because you are subscribed to the Google Groups "sage-devel" group. To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+unsubscr...@googlegroups.com. To post to this group, send email to sage-devel@googlegroups.com. Visit this group at http://groups.google.com/group/sage-devel. For more options, visit https://groups.google.com/d/optout.