# construction of product rings Z/nZ x Z/mZ

Hello,

is it possible in Sage to construct a product ring of two integer modulo rings?

When just creating an cartesian_product, it is for example not possible to add its elements:

R5=Integers(5)
R3=Integers(3)
CR=R5.cartesian_product(R3)
elem=CR((3,2)) # ok, element construction
elem*elem # ok
elem+elem # fails
CR.list() #  not implemented
CR.list_of_elements_of_multiplicative_group # not implemented

edit retag close merge delete

Sort by » oldest newest most voted

The code below (following this tutorial) seems to do the trick. I might turn it into an addition to the Sage codebase at some point (it needs documentation and tests for that, at the very least), but I don't have the time. If you feel like doing that, be my guest!

Just save to product_ring.py and, in Sage do sage: %runfile product_ring.py # from command line

or

load product_ring.py # from notebook.

import sage
from sage.rings.ring import Ring
from sage.rings.all import ZZ
from sage.structure.element import RingElement
from sage.categories.category import Category
from sage.structure.unique_representation import UniqueRepresentation
from sage.categories.rings import Rings
from sage.categories.pushout import ConstructionFunctor

class ProductRingElement(RingElement):
def __init__(self, data, parent=None):
if parent is None:
raise ValueError, "The parent must be provided"
self._data = tuple(data)
RingElement.__init__(self,parent)

def _repr_(self):
return "(" + ", ".join(x._repr_() for x in self._data) + ")"

def __cmp__(self, other):
return cmp(self._data, other._data)

C = self.__class__
z = zip(self._data, other._data)
return C(tuple(zz._add_(zz) for zz in z), parent=self.parent())

def _sub_(self, other):
C = self.__class__
z = zip(self._data, other._data)
return C(tuple(zz._sub_(zz) for zz in z), parent=self.parent())

def _mul_(self, other):
C = self.__class__
z = zip(self._data, other._data)
return C(tuple(zz._mul_(zz) for zz in z), parent=self.parent())

def _div_(self, other):
C = self.__class__
z = zip(self._data, other._data)
return C(tuple(zz._div_(zz) for zz in z), parent=self.parent())

def __iter__(self):
r"""
Returns an iterator of the entries of self.
"""
for x in self._data:
yield x

class ProductRing(UniqueRepresentation, Ring):
r"""
The product ring of a finite number of rings, with elementwise addition
and multiplication.
"""
Element = ProductRingElement

def __init__(self,rings, base=ZZ, category=None):
r"""
INPUT:

- rings -- a tuple of rings.
"""
from sage.categories.rings import Rings

if not all(R.is_ring() for R in rings):
raise TypeError("Expected a tuple of rings as input.")
self._rings = tuple(rings)
Ring.__init__(self, base=base, category=category or Rings())

def _repr_(self):
return "Product ring: (" + ", ".join(R._repr_() for R in self._rings) + ")"

def _element_constructor_(self, *args, **kwds):
if len(args) == len(self._rings):
z = zip(self._rings, args)
elif len(args) == 1:
try:
if len(args) != len(self._rings):
raise TypeError  # also if args has no len()
z = zip(self._rings, args)
except TypeError:
z = zip(self._rings, [args for x in self._rings])
else:
raise TypeError("Wrong number of ring elements")
return self.element_class(tuple(zz(zz) for zz in z), parent=self, **kwds)

def _coerce_map_from_(self, S):
if all(R.has_coerce_map_from(S) for R in self._rings):
return True

def __pow__(self,n):
r"""
Returns the n-th power of self as a vector space.
"""
from sage.modules ...
more

Here is part of the problem - the Cartesian product business seems to be about categories, not the actual rings. And it doesn't really give you what you want. In fact, I find this all somewhat disturbing.

sage: type(CR)
sage.sets.cartesian_product.CartesianProduct_with_category
sage: type(R5)
sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic_with_category
sage: elem*elem
(9, 4)
sage: elem.summand_projection(1)
2
sage: type(elem.summand_projection(1))
sage.rings.integer.Integer


You can do it with just the groups, but of course that's not what you want.

more

'You can do it with just the groups' - you mean using summand_projection? 'of course that's not what you want' - yes, I would like something more comfortable

It seems that CR forgot its ring structure, and kept only its multiplicative operation:

sage: elem.parent().category()
Category of Cartesian products of monoids

more

Well, the question is, is there a way to construct the product ring Z/nZ x Z/mZ in sage

I do not know, i asked to the sage.categories specialists.