# HG changeset patch
# User Burcin Erocal <burcin@erocal.org>
# Date 1279186723 -7200
# Node ID 053186693b24935314a71220fd25561875f174de
# Parent  51207796acad184730ea938cafeb9e55af5ca1d5
[mq]: plural_3.patch

diff --git a/sage/algebras/free_algebra.py b/sage/algebras/free_algebra.py
--- a/sage/algebras/free_algebra.py
+++ b/sage/algebras/free_algebra.py
@@ -483,7 +483,7 @@
             -x*y + z
         """
         from sage.matrix.constructor  import Matrix
-        from sage.rings.polynomial.plural import MPolynomialRing_plural
+        from sage.rings.polynomial.plural import NCPolynomialRing_plural
         
         base_ring=self.base_ring()
         n=self.ngens()
@@ -515,7 +515,7 @@
             if d_poly:
                 dmat[v2_ind,v1_ind]=d_poly
         
-        return MPolynomialRing_plural(base_ring, n, ",".join([str(g) for g in self.gens()]), c=cmat, d=dmat,order=order)
+        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
diff --git a/sage/libs/singular/function.pxd b/sage/libs/singular/function.pxd
--- a/sage/libs/singular/function.pxd
+++ b/sage/libs/singular/function.pxd
@@ -28,11 +28,12 @@
 
 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
@@ -78,4 +79,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 --git a/sage/libs/singular/function.pyx b/sage/libs/singular/function.pyx
--- a/sage/libs/singular/function.pyx
+++ b/sage/libs/singular/function.pyx
@@ -80,6 +80,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
+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
@@ -300,17 +304,25 @@
         """
         cdef leftv *v
         self.args = NULL
-        self._ring = ring
+        self._sage_ring = ring
+        if PY_TYPE_CHECK(ring, MPolynomialRing_libsingular):
+            self._singular_ring = (<MPolynomialRing_libsingular>ring)._ring
+        elif PY_TYPE_CHECK(ring, NCPolynomialRing_plural):
+            self._singular_ring = (<NCPolynomialRing_plural>ring)._ring
+        
         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, MPolynomial_libsingular):
-                v = self.append_polynomial(<MPolynomial_libsingular> a)
+            if PY_TYPE_CHECK(a, MPolynomial_libsingular) or \
+                    PY_TYPE_CHECK(a, NCPolynomial_plural):
+                v = self.append_polynomial(a)
 
-            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular):
-                v = self.append_ring(<MPolynomialRing_libsingular> a)
+            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular) or \
+                    PY_TYPE_CHECK(a, NCPolynomialRing_plural):
+                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):
@@ -358,7 +370,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 +399,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 +410,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 +475,29 @@
         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)
+        result = Matrix(self._sage_ring, nrows, ncols)
+        #FIXME: NCPolynomial
         cdef MPolynomial_libsingular p
         for i in xrange(nrows):
             for j in xrange(ncols):
-                p = MPolynomial_libsingular(sage_ring)
+                p = MPolynomial_libsingular(self._sage_ring)
                 p._poly = 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 +510,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 +527,7 @@
                 else:
                     previous = p_iter
                     p_iter = pNext(p_iter)
-            result.append(new_MP(self._ring, first))
+            result.append(new_MP(self._sage_ring, first))
         return free_module(result)
           
     cdef object to_sage_module_element_sequence_destructive( self, ideal *i):
@@ -529,10 +541,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 +573,15 @@
         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
+        if PY_TYPE_CHECK(p, MPolynomial_libsingular):
+            _p = p_Copy((<MPolynomial_libsingular>p)._poly, <ring*>((<MPolynomial_libsingular>p)._parent)._ring)
+        elif PY_TYPE_CHECK(p, NCPolynomial_plural):
+            _p = p_Copy((<NCPolynomial_plural>p)._poly, <ring*>((<NCPolynomial_plural>p)._parent)._ring)
         return self._append(_p, POLY_CMD)
 
     cdef leftv *append_ideal(self,  i) except NULL:
@@ -582,7 +598,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,18 +614,20 @@
         """
         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:
         """
         Append the ring ``r`` to the list.
         """
+        #FIXME
         cdef ring *_r =  <ring*> r._ring
         _r.ref+=1
         return self._append(<void *>_r, RING_CMD)
 
     cdef leftv *append_matrix(self, mat) except NULL:
+        #FIXME
         
         sage_ring = mat.base_ring()
         cdef ring *r=<ring*> (<MPolynomialRing_libsingular> sage_ring)._ring
@@ -620,6 +638,7 @@
         cdef matrix* _m=mpNew(nrows,ncols)
         for i in xrange(nrows):
             for j in xrange(ncols):
+                #FIXME
                 p = p_Copy(
                     (<MPolynomial_libsingular> mat[i,j])._poly, r)
                 _m.m[ncols*i+j]=p
@@ -639,7 +658,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 +689,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 +729,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 +749,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 +791,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 +960,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 +1019,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)
     
@@ -1074,11 +1096,14 @@
         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 PY_TYPE_CHECK(a, MPolynomial_libsingular) or \
+                    PY_TYPE_CHECK(a, NCPolynomial_plural):
                 ring2 = a.parent()
-            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular):
+            elif PY_TYPE_CHECK(a, MPolynomialRing_libsingular) or \
+                    PY_TYPE_CHECK(a, NCPolynomialRing_plural):
                 ring2 = a
             elif PY_TYPE_CHECK(a, int) or PY_TYPE_CHECK(a, long) or PY_TYPE_CHECK(a, basestring):
                 continue
@@ -1138,11 +1163,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 isinstance(R, MPolynomialRing_libsingular):
+        si_ring = (<MPolynomialRing_libsingular>R)._ring
+    else:
+        si_ring = (<NCPolynomialRing_plural>R)._ring
 
     if si_ring != currRing:
         rChangeCurrRing(si_ring)
diff --git a/sage/libs/singular/singular-cdefs.pxi b/sage/libs/singular/singular-cdefs.pxi
--- a/sage/libs/singular/singular-cdefs.pxi
+++ b/sage/libs/singular/singular-cdefs.pxi
@@ -1026,6 +1026,8 @@
       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 *)
diff --git a/sage/rings/ideal_monoid.py b/sage/rings/ideal_monoid.py
--- a/sage/rings/ideal_monoid.py
+++ b/sage/rings/ideal_monoid.py
@@ -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 --git a/sage/rings/polynomial/multi_polynomial_ideal.py b/sage/rings/polynomial/multi_polynomial_ideal.py
--- a/sage/rings/polynomial/multi_polynomial_ideal.py
+++ b/sage/rings/polynomial/multi_polynomial_ideal.py
@@ -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 --git a/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx b/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx
--- a/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx
+++ b/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx
@@ -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 --git a/sage/rings/polynomial/plural.pxd b/sage/rings/polynomial/plural.pxd
--- a/sage/rings/polynomial/plural.pxd
+++ b/sage/rings/polynomial/plural.pxd
@@ -1,9 +1,26 @@
 include "../../libs/singular/singular-cdefs.pxi"
 
-from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular
+from sage.rings.ring cimport Ring
+from sage.structure.element cimport RingElement
 
-cdef class MPolynomialRing_plural(MPolynomialRing_libsingular):
+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(MPolynomialRing_plural):
+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 --git a/sage/rings/polynomial/plural.pyx b/sage/rings/polynomial/plural.pyx
--- a/sage/rings/polynomial/plural.pyx
+++ b/sage/rings/polynomial/plural.pyx
@@ -1,31 +1,59 @@
 include "sage/ext/stdsage.pxi"
 include "sage/ext/interrupt.pxi"
 
-from sage.matrix.constructor  import Matrix
 
-cdef class MPolynomialRing_plural(MPolynomialRing_libsingular):
+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 term_order import TermOrder
+
+cdef class NCPolynomialRing_plural(Ring):
     def __init__(self, base_ring, n, names, c, d, order='degrevlex'):
-        MPolynomialRing_libsingular.__init__(self, base_ring, n, names, order)
-        cdef matrix* matc=mpNew(n,n)
-        cdef matrix* matd=mpNew(n,n)
-        cdef MPolynomial_libsingular f
+        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)
+        #MPolynomialRing_generic.__init__(self, base_ring, n, names, order)
+        #self._has_singular = True
+        assert(n == len(self._names))
         
-        for i from 0 <= i < n:
-            for j from i+1 <= j < n:
-                if int(c[i,j])!=0:
-                    matc.m[n*i+j] = p_ISet(int(c[i,j]), self._ring)
-        if not d is None:
-            #have matrix
-            for i from 0 <= i < n:
-                for j from i+1 <= j < n:
-                    commuted=d[i,j]
-                    if commuted and commuted!=0:
-                        f =self(commuted)
-                        matd.m[n*i+j] = p_Copy(f._poly, self._ring)
-    
-        nc_CallPlural(matc,matd, NULL, NULL, self._ring)
-        id_Delete(<ideal**>&matc, self._ring)
-        id_Delete(<ideal**>&matd, self._ring)
+        self._one_element = new_NCP(self,p_ISet(1, self._ring))
+        self._zero_element = new_NCP(self,NULL)
+
+    def term_order(self):
+        return self.__term_order
 
     def _repr_(self):
         """
@@ -46,7 +74,59 @@
         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())
 
-cdef class ExteriorAlgebra_plural(MPolynomialRing_plural):
+    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):
         """
@@ -61,6 +141,7 @@
             sage: P("x")*P("x")
             0
         """
+        from sage.matrix.constructor  import Matrix
         c=Matrix(n)
         d=Matrix(n)
         for i from 0 <= i < n:
@@ -76,3 +157,546 @@
         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 --git a/sage/rings/ring.pxd b/sage/rings/ring.pxd
--- a/sage/rings/ring.pxd
+++ b/sage/rings/ring.pxd
@@ -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 --git a/sage/rings/ring.pyx b/sage/rings/ring.pyx
--- a/sage/rings/ring.pyx
+++ b/sage/rings/ring.pyx
@@ -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.
