How to construct a new field that is commutative?

58 views
Skip to first unread message

Yuan ZHOU

unread,
Jul 13, 2016, 1:44:50 PM7/13/16
to sage-support
Hi,

I wish to construct a new class ParametricRealField. I implemented it as follows.

class ParametricRealFieldElement(FieldElement):

    def __init__(self, value, parent=None):
        FieldElement.__init__(self, parent) ## this is so that canonical_coercion works.
        self._val = value
        self._parent = parent ## this is so that .parent() works.

    def parent(self):
        return self._parent

    def __hash__(self):
        return hash(self._val)

class ParametricRealField(Field):

    def __init__(self, values=[], names=()):
        NumberField.__init__(self)
        self._element_class = ParametricRealFieldElement
        self._zero_element = ParametricRealFieldElement(0, parent=self)
        self._one_element =  ParametricRealFieldElement(1, parent=self)
        self._gens = [ ParametricRealFieldElement(value, parent=self) for value in values ]

    def _an_element_impl(self):
        return ParametricRealFieldElement(1, parent=self)

    def _coerce_map_from_(self, S):
        return CallableConvertMap(S, self, lambda s: ParametricRealFieldElement(s, parent=self), parent_as_first_arg=False)

    def __call__(self, elt):
        if parent(elt) == self:
            return elt
        return ParametricRealFieldElement(elt, parent=self)

    def _coerce_impl(self, x):
        return self(x)

Then I got an error when running the following code.

sage: K.<a,b> = ParametricRealField([2, 1])

sage: K.is_commutative()

True

sage: K.is_ring()

True

sage: K in CommutativeRings()

False

sage: R = PolynomialRing(K, 'x')

---------------------------------------------------------------------------

TypeError: Base ring <class '__main__.ParametricRealField'> must be a commutative ring.


How can I make K commutative?


Thanks,
Yuan

Vincent Delecroix

unread,
Jul 13, 2016, 1:57:56 PM7/13/16
to sage-s...@googlegroups.com
Please read the extensive documentation at

http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#coercion-and-categories


Concerning your code, you need at least to:

1 - remove the attribute _parent and the method parent in
ParametricRealFieldElement

2 - remove the __call__ in ParametricRealField

3 - call the constructor of FieldElement as in

class ParametricRealFieldElement(FieldElement):
def __init__(self, value, parent=None):
...
...
FieldElement.__init__(self, parent)

4 - call the constructor of Field as in

class ParametricRealField(Field):
def __init__(self, values=[], names=()):
...
...
Field.__init__(self)

Yuan ZHOU

unread,
Jul 17, 2016, 1:57:35 PM7/17/16
to sage-support
Thanks a lot for the instructions. I revised my code as follows.

from sage.structure.coerce_maps import CallableConvertMap

class ParametricRealFieldElement(FieldElement):

    def __init__(self, value, parent=None):
        FieldElement.__init__(self, parent) 
        self._val = value

    def __hash__(self):
        return hash(self._val)

class ParametricRealField(Field):

    def __init__(self, values=[], names=()):
        Field.__init__(self, self)
        self._element_class = ParametricRealFieldElement
        self._zero_element = ParametricRealFieldElement(0, parent=self)
        self._one_element =  ParametricRealFieldElement(1, parent=self)
        self._gens = [ ParametricRealFieldElement(value, parent=self) for value in values ]

    def _an_element_impl(self):
        return ParametricRealFieldElement(1, parent=self)

    def _coerce_map_from_(self, S):
        return CallableConvertMap(S, self, lambda s: ParametricRealFieldElement(s, parent=self), parent_as_first_arg=False)

    def _coerce_impl(self, x):
        return self(x)

Now I have 
sage: K.<a,b> = ParametricRealField([2, 1])

sage: K in CommutativeRings()

True


However, sage: R.<x,y> = PolynomialRing(K) raises NotImplementedError.


I suspect that the _element_constructor_ method of the class ParametricRealField needs to be provided. 

I tried the following in class ParametricRealField(Field):

    def _element_constructor_(self, elt):
        if elt.parent() == self:
            return elt
        return ParametricRealFieldElement(elt, parent=self)

This allows me to construct K and R, but I'm not able to get the generators of R.

sage: K.<a,b> = ParametricRealField([2, 1])

sage: R.<x,y> = PolynomialRing(K)

sage: x

---------------------------------------------------------------------------

TypeError: unsupported operand parent(s) for '*': '<class '__main__.ParametricRealField_with_category'>' and '<class '__main__.ParametricRealField_with_category'>'

Vincent Delecroix

unread,
Jul 22, 2016, 5:08:34 PM7/22/16
to sage-s...@googlegroups.com
Once again: you would better read

http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#coercion-and-categories


1. In this document it is written how to write an Element and a Parent
class. In particular, to write a Parent class (e.g. your
ParametricRealField) you need to set an attribute named `Element` and
not `_element_class`. And this should be done *before* the call to Field
constructor.
(... Though, I wish this would have appeared sooner in the tutorial ...)

2. Next, the proper way to call the Field constructor is

Field.__init__(self)

why do you provide an additional argument?

3. In order to be able to perform algebraic operations with your
elements you need to define the following four methods in
ParametricRealFieldElement

def __neg__(self):
# should return the result of -self

def __invert__(self):
# should return the result of self^(-1)

def _mul_(left, right):
# should return the result of left * right

def _add_(left, right):
# should return the result of left + right

And optionally the following two methods

def _sub_(left, right):
# should return the result of left - right

def _div_(left, right):
# should return the result of left / right

Vincent

Yuan ZHOU

unread,
Jul 22, 2016, 9:41:43 PM7/22/16
to sage-support
Thanks you very much! 
Setting Element = ParametricRealFieldElement in class ParametricRealField(Field) before def __init__ is the key.

By the way, it seems that I need to call Field.__init__(self, self)  as Field constructor, otherwise I got the following error.

<ipython-input-26-4f6c8185301c> in __init__(self, values, names)

      4 

      5     def __init__(self, values=[], names=()):

----> 6         Field.__init__(self)

      7         #self._element_class = ParametricRealFieldElement

      8         self._zero_element = ParametricRealFieldElement(Integer(0), parent=self)


/Users/yzh/sage/src/sage/rings/ring.pyx in sage.rings.ring.IntegralDomain.__init__ (/Users/yzh/sage/src/build/cythonized/sage/rings/ring.c:13965)()

   1539     _default_category = IntegralDomains()

   1540 

-> 1541     def __init__(self, base_ring, names=None, normalize=True, category=None):

   1542         """

   1543         Initialize ``self``.


TypeError: __init__() takes at least 1 positional argument (0 given)

Reply all
Reply to author
Forward
0 new messages