* * *
Initial wrapper for plural.
* * *
MPolynomialRing_plural now accepts matrix parameters to specify commutativity
relations. Added ExteriorAlgebra.
* * *
[mq]: plural_3.patch

diff -r 8dec8b43ccca module_list.py
--- a/module_list.py	Wed Jun 23 20:40:43 2010 -0700
+++ b/module_list.py	Tue Jul 20 14:48:20 2010 +0200
@@ -1302,6 +1302,13 @@
               include_dirs = [SAGE_ROOT +'/local/include/singular'],
               depends = [SAGE_ROOT + "/local/include/libsingular.h"]),
 
+    Extension('sage.rings.polynomial.plural',
+              sources = ['sage/rings/polynomial/plural.pyx'],
+              libraries = ['m', 'readline', 'singular', 'givaro', 'gmpxx', 'gmp'],
+              language="c++",
+              include_dirs = [SAGE_ROOT +'/local/include/singular'],
+              depends = [SAGE_ROOT + "/local/include/libsingular.h"]),
+
     Extension('sage.rings.polynomial.multi_polynomial_libsingular',
               sources = ['sage/rings/polynomial/multi_polynomial_libsingular.pyx'],
               libraries = ['m', 'readline', 'singular', 'givaro', 'gmpxx', 'gmp'],
diff -r 8dec8b43ccca sage/algebras/free_algebra.py
--- a/sage/algebras/free_algebra.py	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/algebras/free_algebra.py	Tue Jul 20 14:48:20 2010 +0200
@@ -68,7 +68,6 @@
 
 import sage.structure.parent_gens
 
-        
 def FreeAlgebra(R, n, names):
     """
     Return the free algebra over the ring `R` on `n`
@@ -451,6 +450,73 @@
         """
         return self.__monoid
     
-                    
+    def g_algebra(self, relations, order='degrevlex'):
+        """
+            
+            The G-Algebra derrived from this algebra by relations.
+            By default is assumed, that two variables commute.
+            
+            TODO:
+            * Coercion doesn't work yet, there is some cheating about assumptions
+            * Check degeneracy conditions
+            Furthermore, the default values interfere with non degeneracy conditions...
+            
+            EXAMPLES:
+            sage: A.<x,y,z>=FreeAlgebra(QQ,3)
+            sage: G=A.g_algebra({y*x:-x*y})
+            sage: (x,y,z)=G.gens()
+            sage: x*y
+            x*y
+            sage: y*x
+            -x*y
+            sage: z*x
+            x*z
+            sage: (x,y,z)=A.gens()
+            sage: G=A.g_algebra({y*x:-x*y+1})
+            sage: (x,y,z)=G.gens()
+            sage: y*x
+            -x*y + 1
+            sage: (x,y,z)=A.gens()
+            sage: G=A.g_algebra({y*x:-x*y+z})
+            sage: (x,y,z)=G.gens()
+            sage: y*x
+            -x*y + z
+        """
+        from sage.matrix.constructor  import Matrix
+        from sage.rings.polynomial.plural import NCPolynomialRing_plural
+        
+        base_ring=self.base_ring()
+        n=self.ngens()
+        cmat=Matrix(base_ring,n)
+        dmat=Matrix(self,n)
+        for i in xrange(n):
+            for j in xrange(i+1,n):
+                cmat[i,j]=1
+        for (to_commute,commuted) in relations.iteritems():
+            #This is dirty, coercion is broken
+            assert isinstance(to_commute,FreeAlgebraElement), to_commute.__class__
+            assert isinstance(commuted,FreeAlgebraElement), commuted
+            ((v1,e1),(v2,e2))=list(list(to_commute)[0][1])
+            assert e1==1
+            assert e2==1
+            assert v1>v2
+            c_coef=None
+            d_poly=None
+            for (c,m) in commuted:
+                if list(m)==[(v2,1),(v1,1)]:
+                    c_coef=c
+                    #buggy coercion workaround
+                    d_poly=commuted-self(c)*self(m)
+                    break
+            assert not c_coef is None,list(m)
+            v2_ind = self.gens().index(v2)
+            v1_ind = self.gens().index(v1)
+            cmat[v2_ind,v1_ind]=c_coef
+            if d_poly:
+                dmat[v2_ind,v1_ind]=d_poly
+        
+        return NCPolynomialRing_plural(base_ring, n, ",".join([str(g) for g in self.gens()]), c=cmat, d=dmat,order=order)
+            
+            
 from sage.misc.cache import Cache
 cache = Cache(FreeAlgebra_generic)
diff -r 8dec8b43ccca sage/libs/singular/function.pxd
--- a/sage/libs/singular/function.pxd	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/libs/singular/function.pxd	Tue Jul 20 14:48:20 2010 +0200
@@ -19,20 +19,24 @@
 from sage.libs.singular.decl cimport ring as singular_ring
 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular
 
+cdef poly* access_singular_poly(p) except <poly*> -1
+cdef singular_ring* access_singular_ring(r) except <singular_ring*> -1
+
 cdef class RingWrap:
     cdef singular_ring *_ring
 
 cdef class Resolution:
     cdef syStrategy *_resolution
-    cdef MPolynomialRing_libsingular base_ring
+    cdef object base_ring
 
 cdef class Converter(SageObject):
     cdef leftv *args
-    cdef MPolynomialRing_libsingular _ring
+    cdef object _sage_ring
+    cdef singular_ring* _singular_ring
     cdef leftv* pop_front(self) except NULL
     cdef leftv * _append_leftv(self, leftv *v)
     cdef leftv * _append(self, void* data, int res_type)
-    cdef leftv * append_polynomial(self, MPolynomial_libsingular p) except NULL
+    cdef leftv * append_polynomial(self, p) except NULL
     cdef leftv * append_ideal(self,  i) except NULL
     cdef leftv * append_number(self, n) except NULL
     cdef leftv * append_int(self, n) except NULL
@@ -43,7 +47,7 @@
     cdef leftv * append_intvec(self, v) except NULL
     cdef leftv * append_list(self, l) except NULL
     cdef leftv * append_matrix(self, a) except NULL
-    cdef leftv * append_ring(self, MPolynomialRing_libsingular r) except NULL
+    cdef leftv * append_ring(self, r) except NULL
     cdef leftv * append_module(self, m) except NULL
     cdef to_sage_integer_matrix(self, intvec *mat)
     cdef object to_sage_module_element_sequence_destructive(self, ideal *i)
@@ -69,7 +73,7 @@
 
     cdef BaseCallHandler get_call_handler(self)
     cdef bint function_exists(self)
-    cdef MPolynomialRing_libsingular common_ring(self, tuple args, ring=?)
+    cdef common_ring(self, tuple args, ring=?)
 
 cdef class SingularLibraryFunction(SingularFunction):
     pass
@@ -78,4 +82,4 @@
     pass
 
 # the most direct function call interface
-cdef inline call_function(SingularFunction self, tuple args, MPolynomialRing_libsingular R, bint signal_handler=?, object attributes=?)
+cdef inline call_function(SingularFunction self, tuple args, object R, bint signal_handler=?, object attributes=?)
diff -r 8dec8b43ccca sage/libs/singular/function.pyx
--- a/sage/libs/singular/function.pyx	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/libs/singular/function.pyx	Tue Jul 20 14:48:20 2010 +0200
@@ -13,6 +13,8 @@
 - Martin Albrecht (2009-07): clean up, enhancements, etc.
 - Michael Brickenstein (2009-10): extension to more Singular types
 - Martin Albrecht (2010-01): clean up, support for attributes
+- Burcin Erocal (2010-7): plural support
+- Michael Brickenstein (2010-7): plural support
 
 EXAMPLES:
 
@@ -80,6 +82,10 @@
 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, new_MP
 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular
 
+from sage.rings.polynomial.plural cimport NCPolynomialRing_plural, \
+        NCPolynomial_plural, new_NCP
+from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal
+
 from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal
 
 from sage.rings.polynomial.multi_polynomial_ideal_libsingular cimport sage_ideal_to_singular_ideal, singular_ideal_to_sage_sequence
@@ -118,8 +124,7 @@
     
     for (i, p) in enumerate(v):
         component = <int>i+1
-        poly_component = p_Copy(
-            (<MPolynomial_libsingular>p)._poly, r)
+        poly_component = copy_sage_polynomial_into_singular_poly(p)
         p_iter = poly_component
         while p_iter!=NULL:
             p_SetComp(p_iter, component, r)
@@ -128,6 +133,7 @@
         res=p_Add_q(res, poly_component, r)
     return res
 
+
 cdef class RingWrap:
     """
     A simple wrapper around Singular's rings.
@@ -166,8 +172,9 @@
            sage: M = syz(I)
            sage: resolution = mres(M, 0)
         """
-        assert PY_TYPE_CHECK(base_ring, MPolynomialRing_libsingular)
-        self.base_ring = <MPolynomialRing_libsingular> base_ring
+        #FIXME: still not working noncommutative
+        assert is_sage_wrapper_for_singular_ring(base_ring)
+        self.base_ring = base_ring
     def __repr__(self):
         """
         EXAMPLE::
@@ -225,26 +232,98 @@
     args.CleanUp()
     omFreeBin(args, sleftv_bin)
 
+# =====================================
+# = Singular/Plural Abstraction Layer =
+# =====================================
 
-def all_polynomials(s):
+def is_sage_wrapper_for_singular_ring(ring):
+    if PY_TYPE_CHECK(ring, MPolynomialRing_libsingular):
+        return True
+    if PY_TYPE_CHECK(ring, NCPolynomialRing_plural):
+        return True
+    return False
+
+cdef new_sage_polynomial(ring,  poly *p):
+    if PY_TYPE_CHECK(ring, MPolynomialRing_libsingular):
+        return new_MP(ring, p)
+    else:
+        if PY_TYPE_CHECK(ring, NCPolynomialRing_plural):
+            return new_NCP(ring, p)
+    raise ValueError("not a singular or plural ring")
+
+def is_singular_poly_wrapper(p):
+    """
+        checks if p is some data type corresponding to some singular ``poly```.
+        
+        EXAMPLE::
+            sage: from sage.rings.polynomial.plural import NCPolynomialRing_plural
+            sage: from sage.matrix.constructor  import Matrix
+            sage: from sage.libs.singular.function import is_singular_poly_wrapper
+            sage: c=Matrix(2)
+            sage: c[0,1]=-1
+            sage: P = NCPolynomialRing_plural(QQ, 2, 'x,y', c=c, d=Matrix(2))
+            sage: (x,y)=P.gens()
+            sage: is_singular_poly_wrapper(x+y)
+            True
+        
+    """
+    return PY_TYPE_CHECK(p, MPolynomial_libsingular) or PY_TYPE_CHECK(p,  NCPolynomial_plural)
+
+def all_singular_poly_wrapper(s):
     """
     Tests for a sequence ``s``, whether it consists of
     singular polynomials.
     
     EXAMPLE::
         
-        sage: from sage.libs.singular.function import all_polynomials
+        sage: from sage.libs.singular.function import all_singular_poly_wrapper
         sage: P.<x,y,z> = QQ[]
-        sage: all_polynomials([x+1, y])
+        sage: all_singular_poly_wrapper([x+1, y])
         True
-        sage: all_polynomials([x+1, y, 1])
+        sage: all_singular_poly_wrapper([x+1, y, 1])
         False
     """
     for p in s:
-        if not isinstance(p, MPolynomial_libsingular):
+        if not is_singular_poly_wrapper(p):
             return False
     return True
 
+cdef poly* access_singular_poly(p) except <poly*> -1:
+    """
+        Get the raw ``poly`` pointer from a wrapper object
+        EXAMPLE::
+            # sage: P.<a,b,c> = PolynomialRing(QQ)
+            #  sage: p=a+b
+            #  sage: from sage.libs.singular.function import access_singular_poly
+            #  sage: access_singular_poly(p)
+    """
+    if PY_TYPE_CHECK(p, MPolynomial_libsingular):
+        return (<MPolynomial_libsingular> p)._poly
+    else:
+        if PY_TYPE_CHECK(p, NCPolynomial_plural):
+            return (<NCPolynomial_plural> p)._poly
+    raise ValueError("not a singular polynomial wrapper")
+
+cdef ring* access_singular_ring(r) except <ring*> -1:
+    """
+        Get the singular ``ring`` pointer from a 
+        wrapper object.
+        
+        EXAMPLE::
+            # sage: P.<x,y,z> = QQ[]
+            # sage: from sage.libs.singular.function import access_singular_ring
+            # sage: access_singular_ring(P)
+
+    """
+    if PY_TYPE_CHECK(r, MPolynomialRing_libsingular):
+        return (<MPolynomialRing_libsingular> r )._ring
+    if PY_TYPE_CHECK(r, NCPolynomialRing_plural):
+        return (<NCPolynomialRing_plural> r )._ring
+    raise ValueError("not a singular polynomial ring wrapper")
+  
+cdef poly* copy_sage_polynomial_into_singular_poly(p):
+    return p_Copy(access_singular_poly(p), access_singular_ring(p.parent()))
+
 def all_vectors(s):
     """
     Checks if a sequence ``s`` consists of free module
@@ -265,13 +344,17 @@
         False
     """
     for p in s:
-        if not (isinstance(p, FreeModuleElement_generic_dense)\
-            and isinstance(p.parent().base_ring(), MPolynomialRing_libsingular)):
+        if not (PY_TYPE_CHECK(p, FreeModuleElement_generic_dense)\
+            and is_sage_wrapper_for_singular_ring(p.parent().base_ring())):
             return False
     return True
 
 
 
+
+
+
+
 cdef class Converter(SageObject):
     """
     A :class:`Converter` interfaces between Sage objects and Singular
@@ -300,17 +383,22 @@
         """
         cdef leftv *v
         self.args = NULL
-        self._ring = ring
+        self._sage_ring = ring
+        if ring is not None:
+            self._singular_ring = access_singular_ring(ring)
+        
         from  sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense
         from sage.matrix.matrix_integer_dense import Matrix_integer_dense
+        from sage.matrix.matrix_generic_dense import Matrix_generic_dense
         for a in args:
-            if PY_TYPE_CHECK(a, MPolynomial_libsingular):
-                v = self.append_polynomial(<MPolynomial_libsingular> a)
+            if is_singular_poly_wrapper(a):
+                v = self.append_polynomial(a)
 
-            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular):
-                v = self.append_ring(<MPolynomialRing_libsingular> a)
+            elif is_sage_wrapper_for_singular_ring(a):
+                v = self.append_ring(a)
 
-            elif PY_TYPE_CHECK(a, MPolynomialIdeal):
+            elif PY_TYPE_CHECK(a, MPolynomialIdeal) or \
+                    PY_TYPE_CHECK(a, NCPolynomialIdeal):
                 v = self.append_ideal(a)
 
             elif PY_TYPE_CHECK(a, int) or PY_TYPE_CHECK(a, long):
@@ -324,14 +412,17 @@
 
             elif PY_TYPE_CHECK(a, Matrix_integer_dense):
                 v = self.append_intmat(a)
-
+            
+            elif PY_TYPE_CHECK(a, Matrix_generic_dense) and\
+                is_sage_wrapper_for_singular_ring(a.parent().base_ring()):
+                self.append_matrix(a)
+            
             elif PY_TYPE_CHECK(a, Resolution):
                 v = self.append_resolution(a)
 
             elif PY_TYPE_CHECK(a, FreeModuleElement_generic_dense)\
-                and isinstance(
-                    a.parent().base_ring(),
-                    MPolynomialRing_libsingular):
+                and is_sage_wrapper_for_singular_ring(
+                    a.parent().base_ring()):
                 v = self.append_vector(a)
                 
             # as output ideals get converted to sequences
@@ -339,7 +430,7 @@
             # this means, that Singular lists should not be converted to Sequences,
             # as we do not want ambiguities
             elif PY_TYPE_CHECK(a, Sequence)\
-                and all_polynomials(a):
+                and all_singular_poly_wrapper(a):
                 v = self.append_ideal(ring.ideal(a))
             elif PY_TYPE_CHECK(a, Sequence)\
                 and all_vectors(a):
@@ -358,7 +449,7 @@
                     v = self.append_intvec(a)
                 else:
                     v = self.append_list(a)
-            elif a.parent() is self._ring.base_ring():
+            elif a.parent() is self._sage_ring.base_ring():
                 v = self.append_number(a)
 
             elif PY_TYPE_CHECK(a, Integer):
@@ -387,7 +478,7 @@
             sage: Converter([a,b,c],ring=P).ring()
             Multivariate Polynomial Ring in a, b, c over Finite Field of size 127
         """
-        return self._ring
+        return self._sage_ring
 
     def _repr_(self):
         """
@@ -398,7 +489,7 @@
             sage: Converter([a,b,c],ring=P) # indirect doctest
             Singular Converter in Multivariate Polynomial Ring in a, b, c over Finite Field of size 127
         """
-        return "Singular Converter in %s"%(self._ring)
+        return "Singular Converter in %s"%(self._sage_ring)
 
     def __dealloc__(self):
         if self.args:
@@ -463,29 +554,26 @@
         Convert singular matrix to matrix over the polynomial ring.
         """
         from sage.matrix.constructor import Matrix
-        sage_ring = self._ring
-        cdef ring *singular_ring = (<MPolynomialRing_libsingular>\
-            sage_ring)._ring
+        #cdef ring *singular_ring = (<MPolynomialRing_libsingular>\
+        #    self._sage_ring)._ring
         ncols = mat.ncols
         nrows = mat.nrows
-        result = Matrix(sage_ring, nrows, ncols)
-        cdef MPolynomial_libsingular p
+        result = Matrix(self._sage_ring, nrows, ncols)
         for i in xrange(nrows):
             for j in xrange(ncols):
-                p = MPolynomial_libsingular(sage_ring)
-                p._poly = mat.m[i*ncols+j]
+                p = new_sage_polynomial(self._sage_ring, mat.m[i*ncols+j])
                 mat.m[i*ncols+j]=NULL
                 result[i,j] = p
         return result
     
     cdef to_sage_vector_destructive(self, poly *p, free_module = None):
-        cdef ring *r=self._ring._ring
+        #cdef ring *r=self._ring._ring
         cdef int rank
         if free_module:
             rank = free_module.rank()
         else:
-            rank = singular_vector_maximal_component(p, r)
-            free_module = self._ring**rank
+            rank = singular_vector_maximal_component(p, self._singular_ring)
+            free_module = self._sage_ring**rank
         cdef poly *acc
         cdef poly *p_iter
         cdef poly *first
@@ -498,9 +586,9 @@
             first = NULL
             p_iter=p
             while p_iter != NULL:
-                if p_GetComp(p_iter, r) == i:
-                    p_SetComp(p_iter,0, r)
-                    p_Setm(p_iter, r)
+                if p_GetComp(p_iter, self._singular_ring) == i:
+                    p_SetComp(p_iter,0, self._singular_ring)
+                    p_Setm(p_iter, self._singular_ring)
                     if acc == NULL:
                         first = p_iter
                     else:
@@ -515,7 +603,8 @@
                 else:
                     previous = p_iter
                     p_iter = pNext(p_iter)
-            result.append(new_MP(self._ring, first))
+            
+            result.append(new_sage_polynomial(self._sage_ring, first))
         return free_module(result)
           
     cdef object to_sage_module_element_sequence_destructive( self, ideal *i):
@@ -529,10 +618,10 @@
         - ``r`` -- a SINGULAR ring
         - ``sage_ring`` -- a Sage ring matching r
         """
-        cdef MPolynomialRing_libsingular sage_ring = self._ring
+        #cdef MPolynomialRing_libsingular sage_ring = self._ring
         cdef int j
         cdef int rank=i.rank
-        free_module = sage_ring**rank       
+        free_module = self._sage_ring ** rank       
         l = []
 
         for j from 0 <= j < IDELEMS(i):
@@ -561,11 +650,13 @@
         return result
     
     
-    cdef leftv *append_polynomial(self, MPolynomial_libsingular p) except NULL:
+    cdef leftv *append_polynomial(self, p) except NULL:
         """
         Append the polynomial ``p`` to the list.
         """
-        cdef poly* _p = p_Copy(p._poly, <ring*>(<MPolynomialRing_libsingular>p._parent)._ring)
+        cdef poly* _p
+        _p = copy_sage_polynomial_into_singular_poly(p)
+                
         return self._append(_p, POLY_CMD)
 
     cdef leftv *append_ideal(self,  i) except NULL:
@@ -582,7 +673,7 @@
         """
         rank = max([v.parent().rank() for v in m])
         cdef ideal *result
-        cdef ring *r = self._ring._ring
+        cdef ring *r = self._singular_ring
         cdef ideal *i
         cdef int j = 0
 
@@ -598,21 +689,21 @@
         """
         Append the number ``n`` to the list.
         """
-        cdef number *_n =  sa2si(n, self._ring._ring)
+        cdef number *_n =  sa2si(n, self._singular_ring)
         return self._append(<void *>_n, NUMBER_CMD)
 
-    cdef leftv *append_ring(self, MPolynomialRing_libsingular r) except NULL:
+    cdef leftv *append_ring(self, r) except NULL:
         """
         Append the ring ``r`` to the list.
         """
-        cdef ring *_r =  <ring*> r._ring
+        cdef ring *_r =  access_singular_ring(r)
         _r.ref+=1
         return self._append(<void *>_r, RING_CMD)
 
     cdef leftv *append_matrix(self, mat) except NULL:
         
         sage_ring = mat.base_ring()
-        cdef ring *r=<ring*> (<MPolynomialRing_libsingular> sage_ring)._ring
+        cdef ring *r=<ring*> access_singular_ring(sage_ring)
 
         cdef poly *p
         ncols = mat.ncols()
@@ -620,8 +711,8 @@
         cdef matrix* _m=mpNew(nrows,ncols)
         for i in xrange(nrows):
             for j in xrange(ncols):
-                p = p_Copy(
-                    (<MPolynomial_libsingular> mat[i,j])._poly, r)
+                #FIXME
+                p = copy_sage_polynomial_into_singular_poly(mat[i,j])
                 _m.m[ncols*i+j]=p
         return self._append(_m, MATRIX_CMD)
 
@@ -639,7 +730,7 @@
         Append the list ``l`` to the list.
         """
         
-        cdef Converter c = Converter(l, self._ring)
+        cdef Converter c = Converter(l, self._sage_ring)
         n = len(c)
 
         cdef lists *singular_list=<lists*>omAlloc0Bin(slists_bin)
@@ -670,7 +761,7 @@
         Append vector ``v`` from free 
         module over polynomial ring.
         """
-        cdef ring *r = self._ring._ring
+        cdef ring *r = self._singular_ring
         cdef poly *p = sage_vector_to_poly(v, r)
         return self._append(<void*> p, VECTOR_CMD)
     
@@ -710,15 +801,17 @@
 
         - ``to_convert`` - a Singular ``leftv``
         """
+        #FIXME
         cdef MPolynomial_libsingular res_poly
         cdef int rtyp = to_convert.rtyp
         cdef lists *singular_list
         cdef Resolution res_resolution
         if rtyp == IDEAL_CMD:
-            return singular_ideal_to_sage_sequence(<ideal*>to_convert.data, self._ring._ring, self._ring)
+            return singular_ideal_to_sage_sequence(<ideal*>to_convert.data, self._singular_ring, self._sage_ring)
 
         elif rtyp == POLY_CMD:
-            res_poly = MPolynomial_libsingular(self._ring)
+            #FIXME
+            res_poly = MPolynomial_libsingular(self._sage_ring)
             res_poly._poly = <poly*>to_convert.data
             to_convert.data = NULL
             #prevent it getting free, when cleaning the leftv
@@ -728,7 +821,7 @@
             return <long>to_convert.data
         
         elif rtyp == NUMBER_CMD:
-            return si2sa(<number *>to_convert.data, self._ring._ring, self._ring.base_ring())
+            return si2sa(<number *>to_convert.data, self._singular_ring, self._sage_ring.base_ring())
 
         elif rtyp == INTVEC_CMD:
             return si2sa_intvec(<intvec *>to_convert.data)
@@ -770,7 +863,7 @@
             return self.to_sage_integer_matrix(
                 <intvec*> to_convert.data)
         elif rtyp == RESOLUTION_CMD:
-            res_resolution = Resolution(self._ring)
+            res_resolution = Resolution(self._sage_ring)
             res_resolution._resolution = <syStrategy*> to_convert.data
             res_resolution._resolution.references += 1
             return res_resolution
@@ -939,7 +1032,7 @@
         """
         return "%s (singular function)" %(self._name)
 
-    def __call__(self, *args, MPolynomialRing_libsingular ring=None, bint interruptible=True, attributes=None):
+    def __call__(self, *args, ring=None, bint interruptible=True, attributes=None):
         """
         Call this function with the provided arguments ``args`` in the
         ring ``R``.
@@ -998,7 +1091,8 @@
         """
         if ring is None:
             ring = self.common_ring(args, ring)
-        if not PY_TYPE_CHECK(ring, MPolynomialRing_libsingular):
+        if not (PY_TYPE_CHECK(ring, MPolynomialRing_libsingular) or \
+                PY_TYPE_CHECK(ring, NCPolynomialRing_plural)):
             raise TypeError("Cannot call Singular function '%s' with ring parameter of type '%s'"%(self._name,type(ring)))
         return call_function(self, args, ring, interruptible, attributes)
     
@@ -1056,7 +1150,7 @@
 
         return prefix + get_docstring(self._name)
 
-    cdef MPolynomialRing_libsingular common_ring(self, tuple args, ring=None):
+    cdef common_ring(self, tuple args, ring=None):
         """
         Return the common ring for the argument list ``args``.
 
@@ -1074,13 +1168,16 @@
         from  sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense
         from sage.matrix.matrix_integer_dense import Matrix_integer_dense
         for a in args:
-            if PY_TYPE_CHECK(a, MPolynomialIdeal):
+            if PY_TYPE_CHECK(a, MPolynomialIdeal) or \
+                    PY_TYPE_CHECK(a, NCPolynomialIdeal):
                 ring2 = a.ring()
-            elif PY_TYPE_CHECK(a, MPolynomial_libsingular):
+            elif is_singular_poly_wrapper(a):
                 ring2 = a.parent()
-            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular):
+            elif is_sage_wrapper_for_singular_ring(a):
                 ring2 = a
-            elif PY_TYPE_CHECK(a, int) or PY_TYPE_CHECK(a, long) or PY_TYPE_CHECK(a, basestring):
+            elif PY_TYPE_CHECK(a, int) or\
+                PY_TYPE_CHECK(a, long) or\
+                PY_TYPE_CHECK(a, basestring):
                 continue
             elif PY_TYPE_CHECK(a, Matrix_integer_dense):
                 continue
@@ -1093,9 +1190,8 @@
             elif PY_TYPE_CHECK(a, Resolution):
                 ring2 = (<Resolution> a).base_ring
             elif PY_TYPE_CHECK(a, FreeModuleElement_generic_dense)\
-                and PY_TYPE_CHECK(
-                    a.parent().base_ring(),
-                     MPolynomialRing_libsingular):
+                and is_sage_wrapper_for_singular_ring(
+                    a.parent().base_ring()):
                 ring2 = a.parent().base_ring()
             elif ring is not None:
                 a.parent() is ring
@@ -1107,7 +1203,7 @@
                 raise ValueError("Rings do not match up.")
         if ring is None:
             raise ValueError("Could not detect ring.")
-        return <MPolynomialRing_libsingular>ring
+        return ring
 
     def __reduce__(self):
         """
@@ -1138,11 +1234,15 @@
         else:
             return cmp(self._name, (<SingularFunction>other)._name)
 
-cdef inline call_function(SingularFunction self, tuple args, MPolynomialRing_libsingular R, bint signal_handler=True, attributes=None):
+cdef inline call_function(SingularFunction self, tuple args, object R, bint signal_handler=True, attributes=None):
     global currRingHdl
     global errorreported
-
-    cdef ring *si_ring = R._ring
+    
+    cdef ring *si_ring
+    if PY_TYPE_CHECK(R, MPolynomialRing_libsingular):
+        si_ring = (<MPolynomialRing_libsingular>R)._ring
+    else:
+        si_ring = (<NCPolynomialRing_plural>R)._ring
 
     if si_ring != currRing:
         rChangeCurrRing(si_ring)
@@ -1370,7 +1470,42 @@
         <Resolution>
         sage: singular_list(resolution)
         [[(-2*y, 2, y + 1, 0), (0, -2, x - 1, 0), (x*y - y, -y + 1, 1, -y), (x^2 + 1, -x - 1, -1, -x)], [(-x - 1, y - 1, 2*x, -2*y)], [(0)]]
-
+        sage: from sage.rings.polynomial.plural import NCPolynomialRing_plural
+        sage: from sage.matrix.constructor  import Matrix
+        sage: c=Matrix(2)
+        sage: c[0,1]=-1
+        sage: P = NCPolynomialRing_plural(QQ, 2, 'x,y', c=c, d=Matrix(2))
+        sage: (x,y)=P.gens()
+        sage: I= Sequence([x*y,x+y], check=False, immutable=True)#P.ideal(x*y,x+y)
+        sage: twostd = singular_function("twostd")
+        sage: twostd(I)
+        [x + y, y^2]
+        sage: M=syz(I)
+        doctest...
+        sage: M
+        [(x + y, x*y)]
+        sage: syz(M, ring=P)
+        [(0)]
+        sage: mres(I, 0)
+        <Resolution>
+        sage: M=P**3
+        sage: v=M((100*x,5*y,10*y*x*y))
+        sage: leadcoef(v)
+        -10
+        sage: v = M([x+y,x*y+y**3,x])
+        sage: lead(v)
+        (0, y^3)
+        sage: jet(v, 2)
+        (x + y, x*y, x)
+        sage: l = ringlist(P)
+        sage: len(l)
+        6
+        sage: ring(l, ring=P)
+        <RingWrap>
+        sage: I=twostd(I)
+        sage: l[3]=I
+        sage: ring(l, ring=P)
+        <RingWrap>
         
     """
 
diff -r 8dec8b43ccca sage/libs/singular/singular-cdefs.pxi
--- a/sage/libs/singular/singular-cdefs.pxi	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/libs/singular/singular-cdefs.pxi	Tue Jul 20 14:48:20 2010 +0200
@@ -148,6 +148,22 @@
         bint (*nGreaterZero)(number* a)
         void (*nPower)(number* a, int i, number* * result)
 
+    # polynomials
+
+    ctypedef struct poly "polyrec":
+        poly *next
+
+    # ideals
+
+    ctypedef struct ideal "ip_sideal":
+        poly **m # gens array
+        long rank # rank of module, 1 for ideals
+        int nrows # always 1
+        int ncols # number of gens
+        
+    # polynomial procs
+    ctypedef struct p_Procs_s "p_Procs_s":
+        pass
     # rings
 
     ctypedef struct ring "ip_sring":
@@ -160,6 +176,9 @@
         int  CanShortOut # control printing capabilities
         number *minpoly # minpoly for base extension field
         char **names # variable names
+        p_Procs_s *p_Procs #polxnomial procs
+        ideal *qideal #quotient ideal
+        
         char **parameter # parameter names
         ring *algring # base extension field
         short N # number of variables
@@ -197,10 +216,7 @@
         ringorder_Ws
         ringorder_L
 
-    # polynomials
 
-    ctypedef struct poly "polyrec":
-        poly *next
 
         
     # groebner basis options
@@ -210,14 +226,6 @@
         isHomog
         testHomog
 
-    # ideals
-
-    ctypedef struct ideal "ip_sideal":
-        poly **m # gens array
-        long rank # rank of module, 1 for ideals
-        int nrows # always 1
-        int ncols # number of gens
-
     # dense matrices
     
     ctypedef struct matrix "ip_smatrix":
@@ -999,6 +1007,37 @@
 
     cdef int LANG_TOP
 
+# Plural functions
+    
+    int nc_CallPlural(matrix* CC, matrix* DD, poly* CN, poly* DN, ring* r)
+
+# Plural functions
+    
+    int nc_CallPlural(matrix* CC, matrix* DD, poly* CN, poly* DN, ring* r)
+    
+    bint nc_SetupQuotient(ring *, ring *)
+  
+    ctypedef enum nc_type:
+    
+      nc_error # Something's gone wrong!
+      nc_general # yx=q xy+... 
+      nc_skew # yx=q xy 
+      nc_comm # yx= xy 
+      nc_lie,  # yx=xy+... 
+      nc_undef, # for internal reasons */
+      nc_exterior #
+
+    bint rIsPluralRing(ring* r)
+      
+cdef extern from "sca.h":
+    void sca_p_ProcsSet(ring *, p_Procs_s *)
+    
+    void scaFirstAltVar(ring *, int)
+    
+    void scaLastAltVar(ring *, int)
+    
+    void ncRingType(ring *, int)
+    
 cdef extern from "stairc.h":
     # Computes the monomial basis for R[x]/I
     ideal *scKBase(int deg, ideal *s, ideal *Q)
diff -r 8dec8b43ccca sage/modules/free_module.py
--- a/sage/modules/free_module.py	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/modules/free_module.py	Tue Jul 20 14:48:20 2010 +0200
@@ -182,6 +182,8 @@
 from sage.structure.parent_gens import ParentWithGens
 from sage.misc.cachefunc import cached_method
 
+from warnings import warn
+
 ###############################################################################
 #
 # Constructor functions
@@ -345,8 +347,21 @@
         if not isinstance(sparse,bool):
             raise TypeError, "Argument sparse (= %s) must be True or False" % sparse
 
+
+        # We should have two sided, left sided and right sided ideals,
+        # but that's another story ....
+        #
         if not base_ring.is_commutative():
-            raise TypeError, "The base_ring must be a commutative ring."
+            
+            warn("""You are constructing a free module
+             over a noncommutative ring. Sage does 
+             not have a concept of left/right
+             and both sided modules be careful. It's also
+             not guarantied that all multiplications
+             are done from the right side.""")
+            
+        #            raise TypeError, "The base_ring must be a commutative ring."
+
 
         if not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class):
             return RealDoubleVectorSpace_class(rank)
@@ -558,8 +573,10 @@
             Category of modules with basis over Integer Ring
 
         """
-        if not isinstance(base_ring, commutative_ring.CommutativeRing):
-            raise TypeError, "base_ring (=%s) must be a commutative ring"%base_ring
+        if not base_ring.is_commutative():
+            warn("""You are constructing a free module over a noncommutative ring. Sage does not have a concept of left/right and both sided modules be careful. It's also not guarantied that all multiplications are done from the right side.""")
+            #raise TypeError, "base_ring (=%s) must be a commutative ring"%base_ring
+            
         rank = sage.rings.integer.Integer(rank)
         if rank < 0:
             raise ValueError, "rank (=%s) must be nonnegative"%rank
diff -r 8dec8b43ccca sage/rings/ideal_monoid.py
--- a/sage/rings/ideal_monoid.py	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/rings/ideal_monoid.py	Tue Jul 20 14:48:20 2010 +0200
@@ -13,8 +13,8 @@
 
 class IdealMonoid_c(Monoid_class):
     def __init__(self, R):
-        if not is_CommutativeRing(R):
-            raise TypeError, "R must be a commutative ring"
+        #if not is_CommutativeRing(R):
+        #    raise TypeError, "R must be a commutative ring"
         self.__R = R
         ParentWithGens.__init__(self, sage.rings.integer_ring.ZZ)
 
diff -r 8dec8b43ccca sage/rings/polynomial/multi_polynomial_ideal.py
--- a/sage/rings/polynomial/multi_polynomial_ideal.py	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/rings/polynomial/multi_polynomial_ideal.py	Tue Jul 20 14:48:20 2010 +0200
@@ -495,7 +495,117 @@
         B = Sequence([R(e) for e in mgb], R, check=False, immutable=True)
         return B
 
-class MPolynomialIdeal_singular_repr:
+class MPolynomialIdeal_singular_base_repr:
+    @require_field
+    def syzygy_module(self):
+        r"""
+        Computes the first syzygy (i.e., the module of relations of the
+        given generators) of the ideal.
+        
+        EXAMPLE::
+        
+            sage: R.<x,y> = PolynomialRing(QQ)
+            sage: f = 2*x^2 + y
+            sage: g = y
+            sage: h = 2*f + g
+            sage: I = Ideal([f,g,h])
+            sage: M = I.syzygy_module(); M
+            [       -2        -1         1]
+            [       -y 2*x^2 + y         0]
+            sage: G = vector(I.gens())
+            sage: M*G
+            (0, 0)
+        
+        ALGORITHM: Uses Singular's syz command
+        """
+        import sage.libs.singular
+        syz = sage.libs.singular.ff.syz
+        from sage.matrix.constructor import matrix
+
+        #return self._singular_().syz().transpose().sage_matrix(self.ring())
+        S = syz(self)
+        return matrix(self.ring(), S)
+
+    @redSB
+    def _groebner_basis_libsingular(self, algorithm="groebner", redsb=True, red_tail=True):
+        """
+        Return the reduced Groebner basis of this ideal. If the
+        Groebner basis for this ideal has been calculated before the
+        cached Groebner basis is returned regardless of the requested
+        algorithm.
+        
+        INPUT:
+        
+        -  ``algorithm`` - see below for available algorithms
+        - ``redsb`` - return a reduced Groebner basis (default: ``True``)
+        - ``red_tail`` - perform tail reduction (default: ``True``)
+
+        ALGORITHMS:
+        
+        'groebner'
+            Singular's heuristic script (default)
+
+        'std'
+            Buchberger's algorithm
+        
+        'slimgb'
+            the *SlimGB* algorithm
+
+        'stdhilb'
+            Hilbert Basis driven Groebner basis
+        
+        'stdfglm'
+            Buchberger and FGLM
+        
+        EXAMPLES:
+        
+        We compute a Groebner basis of 'cyclic 4' relative to
+        lexicographic ordering. ::
+        
+            sage: R.<a,b,c,d> = PolynomialRing(QQ, 4, order='lex')
+            sage: I = sage.rings.ideal.Cyclic(R,4); I
+            Ideal (a + b + c + d, a*b + a*d + b*c + c*d, a*b*c + a*b*d
+            + a*c*d + b*c*d, a*b*c*d - 1) of Multivariate Polynomial
+            Ring in a, b, c, d over Rational Field
+        
+        ::
+        
+            sage: I._groebner_basis_libsingular()
+            [c^2*d^6 - c^2*d^2 - d^4 + 1, c^3*d^2 + c^2*d^3 - c - d,
+            b*d^4 - b + d^5 - d, b*c - b*d + c^2*d^4 + c*d - 2*d^2,
+            b^2 + 2*b*d + d^2, a + b + c + d]
+        
+        ALGORITHM: Uses libSINGULAR.
+        """
+        from sage.rings.polynomial.multi_polynomial_ideal_libsingular import std_libsingular, slimgb_libsingular
+        from sage.libs.singular import singular_function
+        from sage.libs.singular.option import opt
+
+        import sage.libs.singular
+        groebner = sage.libs.singular.ff.groebner
+
+        opt['redSB'] = redsb
+        opt['redTail'] = red_tail
+
+        T = self.ring().term_order()
+        
+        if algorithm == "std":
+            S = std_libsingular(self)
+        elif algorithm == "slimgb":
+            S = slimgb_libsingular(self)
+        elif algorithm == "groebner":
+            S = groebner(self)
+        else:
+            try:
+                fnc = singular_function(algorithm)
+                S = fnc(self)
+            except NameError:
+                raise NameError("Algorithm '%s' unknown"%algorithm)
+        return S
+    
+
+class MPolynomialIdeal_singular_commutative_repr(
+        MPolynomialIdeal_singular_base_repr):
     """
     An ideal in a multivariate polynomial ring, which has an
     underlying Singular ring associated to it.
@@ -1179,83 +1289,6 @@
         self.__gb_singular = S
         return S
 
-    @redSB
-    def _groebner_basis_libsingular(self, algorithm="groebner", redsb=True, red_tail=True):
-        """
-        Return the reduced Groebner basis of this ideal. If the
-        Groebner basis for this ideal has been calculated before the
-        cached Groebner basis is returned regardless of the requested
-        algorithm.
-        
-        INPUT:
-        
-        -  ``algorithm`` - see below for available algorithms
-        - ``redsb`` - return a reduced Groebner basis (default: ``True``)
-        - ``red_tail`` - perform tail reduction (default: ``True``)
-
-        ALGORITHMS:
-        
-        'groebner'
-            Singular's heuristic script (default)
-
-        'std'
-            Buchberger's algorithm
-        
-        'slimgb'
-            the *SlimGB* algorithm
-
-        'stdhilb'
-            Hilbert Basis driven Groebner basis
-        
-        'stdfglm'
-            Buchberger and FGLM
-        
-        EXAMPLES:
-        
-        We compute a Groebner basis of 'cyclic 4' relative to
-        lexicographic ordering. ::
-        
-            sage: R.<a,b,c,d> = PolynomialRing(QQ, 4, order='lex')
-            sage: I = sage.rings.ideal.Cyclic(R,4); I
-            Ideal (a + b + c + d, a*b + a*d + b*c + c*d, a*b*c + a*b*d
-            + a*c*d + b*c*d, a*b*c*d - 1) of Multivariate Polynomial
-            Ring in a, b, c, d over Rational Field
-        
-        ::
-        
-            sage: I._groebner_basis_libsingular()
-            [c^2*d^6 - c^2*d^2 - d^4 + 1, c^3*d^2 + c^2*d^3 - c - d,
-            b*d^4 - b + d^5 - d, b*c - b*d + c^2*d^4 + c*d - 2*d^2,
-            b^2 + 2*b*d + d^2, a + b + c + d]
-        
-        ALGORITHM: Uses libSINGULAR.
-        """
-        from sage.rings.polynomial.multi_polynomial_ideal_libsingular import std_libsingular, slimgb_libsingular
-        from sage.libs.singular import singular_function
-        from sage.libs.singular.option import opt
-
-        import sage.libs.singular
-        groebner = sage.libs.singular.ff.groebner
-
-        opt['redSB'] = redsb
-        opt['redTail'] = red_tail
-
-        T = self.ring().term_order()
-        
-        if algorithm == "std":
-            S = std_libsingular(self)
-        elif algorithm == "slimgb":
-            S = slimgb_libsingular(self)
-        elif algorithm == "groebner":
-            S = groebner(self)
-        else:
-            try:
-                fnc = singular_function(algorithm)
-                S = fnc(self)
-            except NameError:
-                raise NameError("Algorithm '%s' unknown"%algorithm)
-        return S
-    
     @require_field
     def genus(self):
         """
@@ -1442,36 +1475,6 @@
         ret = Sequence(normalI(self, p, int(r))[0], R, check=False, immutable=True)
         return ret
 
-    @require_field
-    def syzygy_module(self):
-        r"""
-        Computes the first syzygy (i.e., the module of relations of the
-        given generators) of the ideal.
-        
-        EXAMPLE::
-        
-            sage: R.<x,y> = PolynomialRing(QQ)
-            sage: f = 2*x^2 + y
-            sage: g = y
-            sage: h = 2*f + g
-            sage: I = Ideal([f,g,h])
-            sage: M = I.syzygy_module(); M
-            [       -2        -1         1]
-            [       -y 2*x^2 + y         0]
-            sage: G = vector(I.gens())
-            sage: M*G
-            (0, 0)
-        
-        ALGORITHM: Uses Singular's syz command
-        """
-        import sage.libs.singular
-        syz = sage.libs.singular.ff.syz
-        from sage.matrix.constructor import matrix
-
-        #return self._singular_().syz().transpose().sage_matrix(self.ring())
-        S = syz(self)
-        return matrix(self.ring(), S)
-
     @redSB
     def reduced_basis(self):
         r"""
@@ -2271,8 +2274,11 @@
         R = self.ring()
         return R(k)
 
+class NCPolynomialIdeal(MPolynomialIdeal_singular_base_repr, Ideal_generic):
+    def __init__(self, ring, gens, coerce=True):
+        Ideal_generic.__init__(self, ring, gens, coerce=coerce)
 
-class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \
+class MPolynomialIdeal( MPolynomialIdeal_singular_commutative_repr, \
                         MPolynomialIdeal_macaulay2_repr, \
                         MPolynomialIdeal_magma_repr, \
                         Ideal_generic ):
diff -r 8dec8b43ccca sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx
--- a/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx	Tue Jul 20 14:48:20 2010 +0200
@@ -65,16 +65,20 @@
 from sage.libs.singular.decl cimport scKBase, poly, testHomog, idSkipZeroes, idRankFreeModule, kStd
 from sage.libs.singular.decl cimport OPT_REDTAIL, singular_options, kInterRed, t_rep_gb, p_GetCoeff
 from sage.libs.singular.decl cimport nInvers, pp_Mult_nn, p_Delete, n_Delete
+from sage.libs.singular.decl cimport rIsPluralRing
 
 from sage.structure.parent_base cimport ParentWithBase
 
 from sage.rings.polynomial.multi_polynomial_libsingular cimport new_MP
+from sage.rings.polynomial.plural cimport new_NCP
 
 from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal
 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular
 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular
 from sage.structure.sequence import Sequence
 
+from sage.rings.polynomial.plural cimport NCPolynomialRing_plural, NCPolynomial_plural
+
 cdef object singular_ideal_to_sage_sequence(ideal *i, ring *r, object parent):
     """
     convert a SINGULAR ideal to a Sage Sequence (the format Sage
@@ -88,12 +92,18 @@
     """
     cdef int j
     cdef MPolynomial_libsingular p
+    cdef NCPolynomial_plural p_nc
                 
     l = []
 
-    for j from 0 <= j < IDELEMS(i):
-        p = new_MP(parent, p_Copy(i.m[j], r))
-        l.append( p )
+    if rIsPluralRing(r):
+        for j from 0 <= j < IDELEMS(i):
+            p_nc = new_NCP(parent, p_Copy(i.m[j], r))
+            l.append( p_nc )
+    else:
+        for j from 0 <= j < IDELEMS(i):
+            p = new_MP(parent, p_Copy(i.m[j], r))
+            l.append( p )
 
     return Sequence(l, check=False, immutable=True)
 
@@ -113,18 +123,26 @@
     cdef ideal *i
     cdef int j = 0
 
-    if not PY_TYPE_CHECK(R,MPolynomialRing_libsingular):
+    if PY_TYPE_CHECK(R,MPolynomialRing_libsingular):
+        r = (<MPolynomialRing_libsingular>R)._ring
+    elif PY_TYPE_CHECK(R, NCPolynomialRing_plural):
+        r = (<NCPolynomialRing_plural>R)._ring
+    else:
         raise TypeError("Ring must be of type 'MPolynomialRing_libsingular'")
-
-    r = (<MPolynomialRing_libsingular>R)._ring
+        
+    #r = (<MPolynomialRing_libsingular>R)._ring
     rChangeCurrRing(r);
 
     i = idInit(len(gens),1)
     for f in gens:
-        if not PY_TYPE_CHECK(f,MPolynomial_libsingular):
+        if PY_TYPE_CHECK(f,MPolynomial_libsingular):
+            i.m[j] = p_Copy((<MPolynomial_libsingular>f)._poly, r)
+        elif PY_TYPE_CHECK(f, NCPolynomial_plural):
+            i.m[j] = p_Copy((<NCPolynomial_plural>f)._poly, r)
+        else:
             id_Delete(&i, r)
             raise TypeError("All generators must be of type MPolynomial_libsingular.")
-        i.m[j] = p_Copy((<MPolynomial_libsingular>f)._poly, r)
+        #i.m[j] = p_Copy((<MPolynomial_libsingular>f)._poly, r)
         j+=1 
     return i
 
diff -r 8dec8b43ccca sage/rings/polynomial/plural.pxd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/rings/polynomial/plural.pxd	Tue Jul 20 14:48:20 2010 +0200
@@ -0,0 +1,26 @@
+include "../../libs/singular/singular-cdefs.pxi"
+
+from sage.rings.ring cimport Ring
+from sage.structure.element cimport RingElement
+
+cdef class NCPolynomialRing_plural(Ring):
+    cdef object __ngens
+    cdef object __term_order
+    cdef public object _has_singular
+    cdef public object _magma_gens, _magma_cache
+
+    cdef ring *_ring
+#    cdef NCPolynomial_plural _one_element
+#    cdef NCPolynomial_plural _zero_element
+    pass
+
+cdef class ExteriorAlgebra_plural(NCPolynomialRing_plural):
+    pass
+
+cdef class NCPolynomial_plural(RingElement):
+    cdef poly *_poly
+    cpdef _repr_short_(self)
+    cdef long _hash_c(self)
+
+cdef NCPolynomial_plural new_NCP(NCPolynomialRing_plural parent,
+        poly *juice)
diff -r 8dec8b43ccca sage/rings/polynomial/plural.pyx
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/rings/polynomial/plural.pyx	Tue Jul 20 14:48:20 2010 +0200
@@ -0,0 +1,741 @@
+include "sage/ext/stdsage.pxi"
+include "sage/ext/interrupt.pxi"
+
+
+from sage.libs.singular.function cimport RingWrap
+from sage.structure.parent_base cimport ParentWithBase
+from sage.structure.parent_gens cimport ParentWithGens
+
+from sage.rings.integer cimport Integer
+from sage.structure.element cimport Element, ModuleElement
+
+from sage.libs.singular.polynomial cimport singular_polynomial_call, singular_polynomial_cmp, singular_polynomial_add, singular_polynomial_sub, singular_polynomial_neg, singular_polynomial_pow, singular_polynomial_mul, singular_polynomial_rmul
+from sage.libs.singular.polynomial cimport singular_polynomial_deg, singular_polynomial_str_with_changed_varnames, singular_polynomial_latex, singular_polynomial_str, singular_polynomial_div_coeff
+
+from sage.libs.singular.singular cimport si2sa, sa2si, overflow_check
+from sage.rings.integer_ring import ZZ
+from term_order import TermOrder
+
+cdef class NCPolynomialRing_plural(Ring):
+    def __init__(self, base_ring, n, names, c, d, order='degrevlex'):
+        order = TermOrder(order,n)
+        n = int(n)
+        if n < 0:
+            raise ValueError, "Multivariate Polynomial Rings must " + \
+                  "have more than 0 variables."
+        self.__ngens = n
+        self.__term_order = order
+
+        from sage.rings.polynomial.polynomial_ring_constructor import \
+                PolynomialRing
+        P = PolynomialRing(base_ring, n, names, order)
+        c = c.change_ring(P)
+        d = d.change_ring(P)
+        #print "c:",c
+        #print "c.parent()",c.parent()
+        #print "type(c):",type(c)
+        #print "d:",d
+        #print "d.parent()",d.parent()
+        #print "type(d):",type(d)
+        from sage.libs.singular.function import singular_function
+        ncalgebra = singular_function('nc_algebra')
+        cdef RingWrap rw = ncalgebra(c, d, ring = P)
+        self._ring = rw._ring
+        self._ring.ShortOut = 0
+
+        self.__ngens = n
+        ParentWithGens.__init__(self, base_ring, names)
+        self._populate_coercion_lists_()
+        
+        #MPolynomialRing_generic.__init__(self, base_ring, n, names, order)
+        #self._has_singular = True
+        assert(n == len(self._names))
+        
+        self._one_element = new_NCP(self,p_ISet(1, self._ring))
+        self._zero_element = new_NCP(self,NULL)
+    
+    
+    def _element_constructor_(self, x):
+       """
+       Make sure x is a valid member of self, and return the constructed element. 
+       """
+       if x==0:
+           return self._zero_element
+       raise NotImplementedError("not able to constructor "+repr(x))
+        
+    def _coerce_map_from_(self, S):
+       """
+       The only things that coerce into this ring are:
+           - the integer ring
+           - other localizations away from fewer primes
+       """
+       if S is ZZ:
+           return True
+       
+    def __pow__(self, n, _):
+        """
+        Return the free module of rank `n` over this ring.
+
+        EXAMPLES::
+
+        """
+        import sage.modules.all 
+        return sage.modules.all.FreeModule(self, n)
+    
+    
+    
+    def term_order(self):
+        return self.__term_order
+
+
+    def is_commutative(self):
+        return False
+    
+    def is_field(self):
+        return False
+    
+    def _repr_(self):
+        """
+        EXAMPLE:
+            sage: from sage.rings.polynomial.plural import MPolynomialRing_plural
+            sage: from sage.matrix.constructor  import Matrix
+            sage: c=Matrix(2)
+            sage: c[0,1]=-1
+            sage: P = MPolynomialRing_plural(QQ, 2, 'x,y', c=c, d=Matrix(2))
+            sage: P # indirect doctest
+            Noncommutative Multivariate Polynomial Ring in x, y over Rational Field
+            sage: P("x")*P("y")
+            x*y
+            sage: P("y")*P("x")
+            -x*y
+        """
+#TODO: print the relations
+        varstr = ", ".join([ rRingVar(i,self._ring)  for i in range(self.__ngens) ])
+        return "Noncommutative Multivariate Polynomial Ring in %s over %s"%(varstr,self.base_ring())
+
+    def ngens(self):
+        """
+        EXAMPLES::
+        """
+        return int(self.__ngens)
+
+    def gen(self, int n=0):
+        cdef poly *_p
+        cdef ring *_ring = self._ring
+
+        if n < 0 or n >= self.__ngens:
+            raise ValueError, "Generator not defined."
+
+        rChangeCurrRing(_ring)
+        _p = p_ISet(1,_ring)
+        p_SetExp(_p, n+1, 1, _ring)
+        p_Setm(_p, _ring);
+
+        return new_NCP(self,_p)
+
+    def ideal(self, *gens, **kwds):
+        """
+        Create an ideal in this polynomial ring.
+
+        INPUT:
+ 
+        - ``*gens`` - list or tuple of generators (or several input arguments)
+
+        - ``coerce`` - bool (default: ``True``); this must be a
+          keyword argument. Only set it to ``False`` if you are certain
+          that each generator is already in the ring.
+
+        EXAMPLES::
+
+        """
+        from sage.rings.polynomial.multi_polynomial_ideal import \
+                NCPolynomialIdeal
+        coerce = kwds.get('coerce', True)
+        if len(gens) == 1:
+            gens = gens[0]
+        #if is_SingularElement(gens):
+        #    gens = list(gens)
+        #    coerce = True
+        #elif is_Macaulay2Element(gens):
+        #    gens = list(gens)
+        #    coerce = True
+        if not isinstance(gens, (list, tuple)):
+            gens = [gens]
+        if coerce:
+            gens = [self(x) for x in gens]  # this will even coerce from singular ideals correctly!
+        return NCPolynomialIdeal(self, gens, coerce=False)
+
+cdef class ExteriorAlgebra_plural(NCPolynomialRing_plural):
+    """docstring for ExteriorAlgebra_plural"""
+    def __init__(self, base_ring, n, names):
+        """
+        EXAMPLE:
+            sage: from sage.rings.polynomial.plural import ExteriorAlgebra_plural
+
+            sage: P = ExteriorAlgebra_plural(QQ, 3, 'x,y,z')
+            sage: P("x")*P("y")
+            x*y
+            sage: P("y")*P("x")
+            -x*y
+            sage: P("x")*P("x")
+            0
+        """
+        from sage.matrix.constructor  import Matrix
+        c=Matrix(n)
+        d=Matrix(n)
+        for i from 0 <= i < n:
+            for j from i+1 <= j < n:
+                c[i,j]=-1
+        
+        super(ExteriorAlgebra_plural, self).__init__(base_ring, n,names,c=c,d=d)
+        self.setupQuotient()
+        
+    def setupQuotient(self):
+        cdef int n=int(self.ngens())
+        ncRingType( self._ring, nc_exterior );
+        scaFirstAltVar( self._ring, 1);
+        scaLastAltVar( self._ring, n );
+        sca_p_ProcsSet(self._ring, self._ring.p_Procs);
+
+
+cdef class NCPolynomial_plural(RingElement):
+    def __init__(self, NCPolynomialRing_plural parent):
+        self._poly = NULL
+        self._parent = <ParentWithBase>parent
+
+    def __dealloc__(self):
+        # TODO: Warn otherwise!
+        # for some mysterious reason, various things may be NULL in some cases
+        if self._parent is not <ParentWithBase>None and (<NCPolynomialRing_plural>self._parent)._ring != NULL and self._poly != NULL:
+            p_Delete(&self._poly, (<NCPolynomialRing_plural>self._parent)._ring)
+
+    def __hash__(self):
+        """
+        This hash incorporates the variable name in an effort to
+        respect the obvious inclusions into multi-variable polynomial
+        rings.
+
+        The tuple algorithm is borrowed from http://effbot.org/zone/python-hash.htm.
+
+        EXAMPLES::
+
+            sage: R.<x>=QQ[]
+            sage: S.<x,y>=QQ[]
+            sage: hash(S(1/2))==hash(1/2)  # respect inclusions of the rationals
+            True
+            sage: hash(S.0)==hash(R.0)  # respect inclusions into mpoly rings
+            True
+            sage: # the point is to make for more flexible dictionary look ups
+            sage: d={S.0:12}
+            sage: d[R.0]
+            12
+        """
+        return self._hash_c()
+
+    def __richcmp__(left, right, int op):
+        """
+        Compare left and right and return -1, 0, and 1 for <,==, and >
+        respectively.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z> = PolynomialRing(QQ,order='degrevlex')
+            sage: x == x
+            True
+
+            sage: x > y
+            True
+            sage: y^2 > x
+            True
+
+            sage: (2/3*x^2 + 1/2*y + 3) > (2/3*x^2 + 1/4*y + 10)
+            True
+
+        TESTS::
+
+            sage: P.<x,y,z> = PolynomialRing(QQ, order='degrevlex')
+            sage: x > P(0)
+            True
+
+            sage: P(0) == P(0)
+            True
+
+            sage: P(0) < P(1)
+            True
+
+            sage: x > P(1)
+            True
+            
+            sage: 1/2*x < 3/4*x
+            True
+
+            sage: (x+1) > x
+            True
+
+            sage: f = 3/4*x^2*y + 1/2*x + 2/7
+            sage: f > f
+            False
+            sage: f < f
+            False
+            sage: f == f
+            True
+
+            sage: P.<x,y,z> = PolynomialRing(GF(127), order='degrevlex')
+            sage: (66*x^2 + 23) > (66*x^2 + 2)
+            True
+        """
+        return (<Element>left)._richcmp(right, op)
+
+    cdef int _cmp_c_impl(left, Element right) except -2:
+        if left is right:
+            return 0
+        cdef poly *p = (<NCPolynomial_plural>left)._poly
+        cdef poly *q = (<NCPolynomial_plural>right)._poly
+        cdef ring *r = (<NCPolynomialRing_plural>left._parent)._ring
+        return singular_polynomial_cmp(p, q, r)
+
+    cpdef ModuleElement _add_( left, ModuleElement right):
+        """
+        Add left and right.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z>=PolynomialRing(QQ,3)
+            sage: 3/2*x + 1/2*y + 1
+            3/2*x + 1/2*y + 1
+
+        """
+        cdef poly *_p
+        singular_polynomial_add(&_p, left._poly, 
+                                 (<NCPolynomial_plural>right)._poly,
+                                 (<NCPolynomialRing_plural>left._parent)._ring)
+        return new_NCP((<NCPolynomialRing_plural>left._parent), _p)
+
+    cpdef ModuleElement _sub_( left, ModuleElement right):
+        """
+        Subtract left and right.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z>=PolynomialRing(QQ,3)
+            sage: 3/2*x - 1/2*y - 1
+            3/2*x - 1/2*y - 1
+
+        """
+        cdef ring *_ring = (<NCPolynomialRing_plural>left._parent)._ring
+
+        cdef poly *_p
+        singular_polynomial_sub(&_p, left._poly, 
+                                (<NCPolynomial_plural>right)._poly,
+                                _ring)
+        return new_NCP((<NCPolynomialRing_plural>left._parent), _p)
+
+    cpdef ModuleElement _rmul_(self, RingElement left):
+        """
+        Multiply self with a base ring element.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z>=PolynomialRing(QQ,3)
+            sage: 3/2*x
+            3/2*x
+        """
+
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+        if not left:
+            return (<NCPolynomialRing_plural>self._parent)._zero_element
+        cdef poly *_p
+        singular_polynomial_rmul(&_p, self._poly, left, _ring)
+        return new_NCP((<NCPolynomialRing_plural>self._parent),_p)
+        
+    cpdef ModuleElement _lmul_(self, RingElement right):
+        # all currently implemented rings are commutative
+        return self._rmul_(right)
+        
+    cpdef RingElement  _mul_(left, RingElement right):
+        """
+        Multiply left and right.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z>=PolynomialRing(QQ,3)
+            sage: (3/2*x - 1/2*y - 1) * (3/2*x + 1/2*y + 1)
+            9/4*x^2 - 1/4*y^2 - y - 1
+
+            sage: P.<x,y> = PolynomialRing(QQ,order='lex')
+            sage: (x^2^30) * x^2^30
+            Traceback (most recent call last):
+            ...
+            OverflowError: Exponent overflow (...).
+        """
+        # all currently implemented rings are commutative
+        cdef poly *_p
+        singular_polynomial_mul(&_p, left._poly, 
+                                 (<NCPolynomial_plural>right)._poly, 
+                                 (<NCPolynomialRing_plural>left._parent)._ring)
+        return new_NCP((<NCPolynomialRing_plural>left._parent),_p)
+
+    cpdef RingElement _div_(left, RingElement right):
+        """
+        Divide left by right
+
+        EXAMPLES::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: f = (x + y)/3
+            sage: f.parent()
+            Multivariate Polynomial Ring in x, y over Rational Field
+
+        Note that / is still a constructor for elements of the
+        fraction field in all cases as long as both arguments have the
+        same parent and right is not constant. ::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: f = x^3 + y
+            sage: g = x
+            sage: h = f/g; h
+            (x^3 + y)/x
+            sage: h.parent()
+            Fraction Field of Multivariate Polynomial Ring in x, y over Rational Field
+
+        If we divide over `\ZZ` the result is the same as multiplying
+        by 1/3 (i.e. base extension). ::
+        
+            sage: R.<x,y> = ZZ[]
+            sage: f = (x + y)/3      
+            sage: f.parent()
+            Multivariate Polynomial Ring in x, y over Rational Field
+            sage: f = (x + y) * 1/3      
+            sage: f.parent()
+            Multivariate Polynomial Ring in x, y over Rational Field
+            
+        But we get a true fraction field if the denominator is not in
+        the fraction field of the base ring.""
+        
+            sage: f = x/y
+            sage: f.parent()
+            Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring
+
+        Division will fail for non-integral domains::
+
+            sage: P.<x,y> = Zmod(1024)[]
+            sage: x/P(3)
+            Traceback (most recent call last):
+            ...
+            TypeError: self must be an integral domain.
+
+            sage: x/3
+            Traceback (most recent call last):
+            ...
+            TypeError: self must be an integral domain.
+
+        TESTS::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: x/0
+            Traceback (most recent call last):
+            ...
+            ZeroDivisionError: rational division by zero
+        """
+        cdef poly *p 
+        cdef bint is_field = left._parent._base.is_field()
+        if p_IsConstant((<NCPolynomial_plural>right)._poly, (<NCPolynomialRing_plural>right._parent)._ring):
+            if is_field:
+                singular_polynomial_div_coeff(&p, left._poly, (<NCPolynomial_plural>right)._poly, (<NCPolynomialRing_plural>right._parent)._ring)
+                return new_NCP(left._parent, p)
+            else:
+                return left.change_ring(left.base_ring().fraction_field())/right
+        else:
+            return (<NCPolynomialRing_plural>left._parent).fraction_field()(left,right)
+
+    def __pow__(NCPolynomial_plural self, exp, ignored):
+        """
+        Return ``self**(exp)``.
+
+        The exponent must be an integer.
+
+        EXAMPLES::
+
+            sage: R.<x,y> = PolynomialRing(QQ,2)
+            sage: f = x^3 + y
+            sage: f^2
+            x^6 + 2*x^3*y + y^2
+            sage: g = f^(-1); g
+            1/(x^3 + y)
+            sage: type(g)
+            <type 'sage.rings.fraction_field_element.FractionFieldElement'>
+
+            sage: P.<x,y> = PolynomialRing(ZZ)
+            sage: P(2)**(-1)
+            1/2
+            
+            sage: P.<u,v> = PolynomialRing(QQ, 2)
+            sage: u^(1/2)
+            Traceback (most recent call last):
+            ...
+            TypeError: non-integral exponents not supported
+
+            sage: P.<x,y> = PolynomialRing(QQ,order='lex')
+            sage: (x+y^2^30)^10
+            Traceback (most recent call last):
+            ....
+            OverflowError: Exponent overflow (...).
+        """
+        if not PY_TYPE_CHECK_EXACT(exp, Integer) or \
+                PY_TYPE_CHECK_EXACT(exp, int):
+                    try:
+                        exp = Integer(exp)
+                    except TypeError:
+                        raise TypeError, "non-integral exponents not supported"
+
+        if exp < 0:
+            return 1/(self**(-exp))
+        elif exp == 0:
+            return (<NCPolynomialRing_plural>self._parent)._one_element
+
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+        cdef poly *_p
+        singular_polynomial_pow(&_p, self._poly, exp, _ring)
+        return new_NCP((<NCPolynomialRing_plural>self._parent),_p)
+
+    def __neg__(self):
+        """
+        Return ``-self``.
+
+        EXAMPLES::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: f = x^3 + y
+            sage: -f
+            -x^3 - y
+        """
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+
+        cdef poly *p
+        singular_polynomial_neg(&p, self._poly, _ring)
+        return new_NCP((<NCPolynomialRing_plural>self._parent), p)
+
+    def _repr_(self):
+        """
+        EXAMPLES::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: f = x^3 + y
+            sage: f # indirect doctest
+            x^3 + y
+        """
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+        s = singular_polynomial_str(self._poly, _ring)
+        return s
+
+    cpdef _repr_short_(self):
+        """
+        This is a faster but less pretty way to print polynomials. If
+        available it uses the short SINGULAR notation.
+        
+        EXAMPLES::
+
+            sage: R.<x,y>=PolynomialRing(QQ,2)
+            sage: f = x^3 + y
+            sage: f._repr_short_()
+            'x3+y'
+        """
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+        rChangeCurrRing(_ring)
+        if _ring.CanShortOut:
+            _ring.ShortOut = 1
+            s = p_String(self._poly, _ring, _ring)
+            _ring.ShortOut = 0
+        else:
+            s = p_String(self._poly, _ring, _ring)
+        return s
+                                           
+    def _latex_(self):
+        """
+        Return a polynomial LaTeX representation of this polynomial.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z> = QQ[]
+            sage: f = - 1*x^2*y - 25/27 * y^3 - z^2
+            sage: latex(f)
+            - x^{2} y - \frac{25}{27} y^{3} - z^{2}
+        """
+        cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
+        gens = self.parent().latex_variable_names()
+        base = self.parent().base()
+        return singular_polynomial_latex(self._poly, _ring, base, gens)
+    
+    def _repr_with_changed_varnames(self, varnames):
+        """
+        Return string representing this polynomial but change the
+        variable names to ``varnames``.
+
+        EXAMPLES::
+
+            sage: P.<x,y,z> = QQ[]
+            sage: f = - 1*x^2*y - 25/27 * y^3 - z^2
+            sage: print f._repr_with_changed_varnames(['FOO', 'BAR', 'FOOBAR'])
+            -FOO^2*BAR - 25/27*BAR^3 - FOOBAR^2
+        """
+        return  singular_polynomial_str_with_changed_varnames(self._poly, (<NCPolynomialRing_plural>self._parent)._ring, varnames)
+            
+    def degree(self, NCPolynomial_plural x=None):
+        """
+        Return the maximal degree of this polynomial in ``x``, where
+        ``x`` must be one of the generators for the parent of this
+        polynomial.
+
+        INPUT:
+
+        - ``x`` - multivariate polynomial (a generator of the parent of
+          self) If x is not specified (or is ``None``), return the total
+          degree, which is the maximum degree of any monomial.
+
+        OUTPUT:
+            integer
+        
+        EXAMPLES::
+
+            sage: R.<x, y> = QQ[]
+            sage: f = y^2 - x^9 - x
+            sage: f.degree(x)
+            9
+            sage: f.degree(y)
+            2
+            sage: (y^10*x - 7*x^2*y^5 + 5*x^3).degree(x)
+            3
+            sage: (y^10*x - 7*x^2*y^5 + 5*x^3).degree(y)
+            10
+
+        TESTS::
+
+            sage: P.<x, y> = QQ[]
+            sage: P(0).degree(x)
+            -1
+            sage: P(1).degree(x)
+            0
+
+        """
+        cdef ring *r = (<NCPolynomialRing_plural>self._parent)._ring
+        cdef poly *p = self._poly
+        if not x:
+            return singular_polynomial_deg(p,NULL,r)
+
+        # TODO: we can do this faster
+        if not x in self._parent.gens():
+            raise TypeError("x must be one of the generators of the parent.")
+
+        return singular_polynomial_deg(p, (<NCPolynomial_plural>x)._poly, r)
+
+    def total_degree(self):
+        """
+        Return the total degree of ``self``, which is the maximum degree
+        of all monomials in ``self``.
+
+        EXAMPLES::
+
+            sage: R.<x,y,z> = QQ[]
+            sage: f=2*x*y^3*z^2
+            sage: f.total_degree()
+            6
+            sage: f=4*x^2*y^2*z^3
+            sage: f.total_degree()
+            7
+            sage: f=99*x^6*y^3*z^9
+            sage: f.total_degree()
+            18
+            sage: f=x*y^3*z^6+3*x^2
+            sage: f.total_degree()
+            10
+            sage: f=z^3+8*x^4*y^5*z
+            sage: f.total_degree()
+            10
+            sage: f=z^9+10*x^4+y^8*x^2
+            sage: f.total_degree()
+            10
+
+        TESTS::
+
+            sage: R.<x,y,z> = QQ[]
+            sage: R(0).total_degree()
+            -1
+            sage: R(1).total_degree()
+            0
+        """
+        cdef poly *p = self._poly
+        cdef ring *r = (<NCPolynomialRing_plural>self._parent)._ring
+        return singular_polynomial_deg(p,NULL,r)
+
+    def degrees(self):
+        """ 
+        Returns a tuple with the maximal degree of each variable in
+        this polynomial.  The list of degrees is ordered by the order
+        of the generators.
+
+        EXAMPLES::
+
+            sage: R.<y0,y1,y2> = PolynomialRing(QQ,3)
+            sage: q = 3*y0*y1*y1*y2; q 
+            3*y0*y1^2*y2 
+            sage: q.degrees() 
+            (1, 2, 1)
+            sage: (q + y0^5).degrees()
+            (5, 2, 1)
+        """
+        cdef poly *p = self._poly
+        cdef ring *r = (<NCPolynomialRing_plural>self._parent)._ring
+        cdef int i
+        cdef list d = [0 for _ in range(r.N)]
+        while p:
+            for i from 0 <= i < r.N:
+                d[i] = max(d[i],p_GetExp(p, i+1, r))
+            p = pNext(p)
+        return tuple(d)
+
+    cdef long _hash_c(self):
+        """
+        See ``self.__hash__``
+        """
+        cdef poly *p
+        cdef ring *r
+        cdef int n
+        cdef int v
+        r = (<NCPolynomialRing_plural>self._parent)._ring
+        if r!=currRing: rChangeCurrRing(r)
+        base = (<NCPolynomialRing_plural>self._parent)._base
+        p = self._poly
+        cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap
+        cdef long result_mon
+        var_name_hash = [hash(vn) for vn in self._parent.variable_names()]
+        cdef long c_hash
+        while p:
+            c_hash = hash(si2sa(p_GetCoeff(p, r), r, base))
+            if c_hash != 0: # this is always going to be true, because we are sparse (correct?)
+                # Hash (self[i], gen_a, exp_a, gen_b, exp_b, gen_c, exp_c, ...) as a tuple according to the algorithm.
+                # I omit gen,exp pairs where the exponent is zero.
+                result_mon = c_hash
+                for v from 1 <= v <= r.N:
+                    n = p_GetExp(p,v,r)
+                    if n!=0:
+                        result_mon = (1000003 * result_mon) ^ var_name_hash[v-1]
+                        result_mon = (1000003 * result_mon) ^ n
+                result += result_mon
+
+            p = pNext(p)
+        if result == -1:
+            return -2
+        return result
+
+
+cdef inline NCPolynomial_plural new_NCP(NCPolynomialRing_plural parent,
+        poly *juice):
+    """
+    Construct NCPolynomial_plural from parent and SINGULAR poly.
+    """
+    cdef NCPolynomial_plural p
+    p = PY_NEW(NCPolynomial_plural)
+    p._parent = <ParentWithBase>parent
+    p._poly = juice
+    p_Normalize(p._poly, parent._ring)
+    return p
diff -r 8dec8b43ccca sage/rings/ring.pxd
--- a/sage/rings/ring.pxd	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/rings/ring.pxd	Tue Jul 20 14:48:20 2010 +0200
@@ -5,11 +5,11 @@
     cdef public object _one_element
     cdef public object _zero_ideal
     cdef public object _unit_ideal
+    cdef public object __ideal_monoid
     cdef _an_element_c_impl(self)
 
 cdef class CommutativeRing(Ring):
     cdef public object __fraction_field
-    cdef public object __ideal_monoid
 
 cdef class IntegralDomain(CommutativeRing):
     pass
diff -r 8dec8b43ccca sage/rings/ring.pyx
--- a/sage/rings/ring.pyx	Wed Jun 23 20:40:43 2010 -0700
+++ b/sage/rings/ring.pyx	Tue Jul 20 14:48:20 2010 +0200
@@ -911,6 +911,25 @@
             if not x.is_zero():
                 return x
 
+    def ideal_monoid(self):
+        """
+        Return the monoid of ideals of this ring.
+
+        EXAMPLES::
+
+            sage: ZZ.ideal_monoid()
+            Monoid of ideals of Integer Ring
+            sage: R.<x>=QQ[]; R.ideal_monoid()
+            Monoid of ideals of Univariate Polynomial Ring in x over Rational Field
+        """
+        if self.__ideal_monoid is not None:
+            return self.__ideal_monoid
+        else:
+            from sage.rings.ideal_monoid import IdealMonoid
+            M = IdealMonoid(self)
+            self.__ideal_monoid = M
+            return M
+
 cdef class CommutativeRing(Ring):
     """
     Generic commutative ring.
@@ -1056,25 +1075,6 @@
         """
         raise NotImplementedError
 
-    def ideal_monoid(self):
-        """
-        Return the monoid of ideals of this ring.
-
-        EXAMPLES::
-
-            sage: ZZ.ideal_monoid()
-            Monoid of ideals of Integer Ring
-            sage: R.<x>=QQ[]; R.ideal_monoid()
-            Monoid of ideals of Univariate Polynomial Ring in x over Rational Field
-        """
-        if self.__ideal_monoid is not None:
-            return self.__ideal_monoid
-        else:
-            from sage.rings.ideal_monoid import IdealMonoid
-            M = IdealMonoid(self)
-            self.__ideal_monoid = M
-            return M
-
     def quotient(self, I, names=None):
         """
         Create the quotient of R by the ideal I.
