# HG changeset patch
# User Michael Brickenstein <brickenstein@mfo.de>
# Date 1226934659 -3600
# Node ID 0acacd97c7f38f5afdb0c762b421e12b1ee8c3ea
# Parent  1611ab2e6f45c6b11ace32518e8d36e8231179ed
MPolynomialRing_plural now accepts matrix parameters to specify commutativity
relations. Added ExteriorAlgebra.

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
@@ -55,7 +55,6 @@
 
 import sage.structure.parent_gens
 
-        
 def FreeAlgebra(R, n, names):
     """
     Return the free algebra over the ring $R$ on $n$ generators with
@@ -394,6 +393,71 @@
         """
         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 MPolynomialRing_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)
+            cmat[v2,v1]=c_coef
+            if d_poly:
+                dmat[v2,v1]=d_poly
+        
+        return MPolynomialRing_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 --git a/sage/algebras/free_algebra_element.py b/sage/algebras/free_algebra_element.py
--- a/sage/algebras/free_algebra_element.py
+++ b/sage/algebras/free_algebra_element.py
@@ -57,6 +57,19 @@
             self.__monomial_coefficients = dict([ (A.monoid()(e1),R(e2)) for e1,e2 in x.items()])
         else:
             raise TypeError, "Argument x (= %s) is of the wrong type."%x
+
+    def __iter__(self):
+        """
+        Returns an iterator which yields tuples of coeficient and monoid.
+        
+        EXAMPLES:
+        sage: a = FreeAlgebra(QQ, 5, 'a').gens()
+        sage: list(3*a[0]*a[1]*a[4]**3*a[0]+1)
+        [(1, 1), (3, a0*a1*a4^3*a0)]
+        """
+        for (key,val) in self.__monomial_coefficients.iteritems():
+            yield (val,key)
+    
 
     def _repr_(self):
         """
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
@@ -91,6 +91,22 @@
         napoly *n
         int s
 
+    # 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":
@@ -103,6 +119,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
@@ -134,10 +153,7 @@
         ringorder_Ws
         ringorder_L
 
-    # polynomials
 
-    ctypedef struct poly "polyrec":
-        poly *next
 
         
     # groebner basis options
@@ -146,14 +162,6 @@
         isNotHomog
         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
     
@@ -694,6 +702,31 @@
     
     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 #
+      
+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 --git a/sage/monoids/free_monoid_element.py b/sage/monoids/free_monoid_element.py
--- a/sage/monoids/free_monoid_element.py
+++ b/sage/monoids/free_monoid_element.py
@@ -78,7 +78,16 @@
         else:
             # TODO: should have some other checks here...
             raise TypeError, "Argument x (= %s) is of the wrong type."%x
-
+    def __iter__(self):
+        """
+        Returns an iterator which yields tuples of variable and exponent.
+        
+        EXAMPLES:
+        sage: a = FreeMonoid(5, 'a').gens()
+        sage: list(a[0]*a[1]*a[4]**3*a[0])
+        [(0, 1), (1, 1), (4, 3), (0, 1)]
+        """
+        return iter(self._element_list)
 ##     def __cmp__(left, right):
 ##         """
 ##         Compare two free monoid elements with the same parents.
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
@@ -5,3 +5,5 @@
 cdef class MPolynomialRing_plural(MPolynomialRing_libsingular):
     pass
 
+cdef class ExteriorAlgebra_plural(MPolynomialRing_plural):
+    pass
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,34 +1,78 @@
 include "sage/ext/stdsage.pxi"
 include "sage/ext/interrupt.pxi"
 
+from sage.matrix.constructor  import Matrix
+
 cdef class MPolynomialRing_plural(MPolynomialRing_libsingular):
-    def __init__(self, base_ring, n, names, order='degrevlex'):
+    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
+        
         for i from 0 <= i < n:
             for j from i+1 <= j < n:
-                matc.m[n*i+j] = p_ISet(-1, self._ring)
-
-        for i from 0 <= i < n:
-            for j from i+1 <= j < n:
-                matd.m[n*i+j] = p_ISet(-1, self._ring)
-
-        nc_CallPlural(matc, matd, NULL, NULL, self._ring)
-
+                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)
- 
+
     def _repr_(self):
         """
         EXAMPLE:
-            sage: from sage.rings.polynomial.plural import MPolynomial_plural
-            sage: P = MPolynomialRing_plural(QQ, 2, 'x,y')
+            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
-            Multivariate Polynomial Ring in x, y over Rational Field
+            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())
+
+cdef class ExteriorAlgebra_plural(MPolynomialRing_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
+        """
+        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);
