--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sympy-patches" group.
To post to this group, send email to sympy-patches@googlegroups.com
To unsubscribe from this group, send email to 
sympy-patches+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sympy-patches?hl=en
-~----------~----~----~----~------~----~------~--~---

>From 7ecd197551a476985e18e2fdf9311f8c1731bf2e Mon Sep 17 00:00:00 2001
From: Alan Bromborsky <bro...@ga.(none)>
Date: Sun, 24 May 2009 17:56:07 -0400
Subject: [PATCH] GA-updates:

GA.py -
1. Use << and >> as aliases for left and right multivector contraction so that r-forms are available for both operations.
2. Use div() and curl() as aliases for grad_int() and grad_ext() multivector member functions to make it easier to
remember which is which.
3. Improve multivector __str__() function to eliminate unneeded parenthesis.
4. Add constructor for general symbolic multivector and fix error in spinor multivector constructor.

test_GA.py -
1. Add tests for improved __str__() function.

HTML Documents -

1. Add warnings about precedence behavior of python operators compared to precedence of geometric algebra operators.
2. Add warning about base to blade converstion in __str__()
3. Document constructor for general symbolic multivector.

Example -
1. Removed unnecessary code.
---
 doc/src/modules/galgebra/GA/GAsympy.txt |  207 +++++++++++++++++++++++--------
 sympy/galgebra/GA.py                    |  150 +++++++++++++++++------
 sympy/galgebra/examples/coords.py       |   11 +--
 sympy/galgebra/tests/test_GA.py         |    9 ++
 4 files changed, 278 insertions(+), 99 deletions(-)

diff --git a/doc/src/modules/galgebra/GA/GAsympy.txt b/doc/src/modules/galgebra/GA/GAsympy.txt
index e4b2d4c..dc06135 100644
--- a/doc/src/modules/galgebra/GA/GAsympy.txt
+++ b/doc/src/modules/galgebra/GA/GAsympy.txt
@@ -45,8 +45,8 @@
    python  that utilizes the :mod:`sympy` symbolic algebra library.  The   python
    module :mod:`GA` has been developed for coordinate free calculations using
    the operations (geometric, outer, and inner products etc.) of geometric algebra.
-   The operations can be defined using a completely arbitrary pseudometric defined
-   by the inner products of a set of arbitrary vectors or the pseudometric  can be
+   The operations can be defined using a completely arbitrary metric defined
+   by the inner products of a set of arbitrary vectors or the metric  can be
    restricted to enforce orthogonality and signature constraints on the set of
    vectors.  In addition the module includes the geometric, outer (curl) and inner
    (div) derivatives and the ability to define a curvilinear coordinate  system.
@@ -85,10 +85,10 @@ Several software packages for numerical geometric algebra calculations are
 available from Doran-Lazenby group and the Dorst group. Symbolic packages for
 Clifford algebra using orthongonal bases such as
 :math:`e_{i}e_{j}+e_{j}e_{i} = 2\eta_{ij}`, where :math:`\eta_{ij}` is a numeric
-array are available from the  Doran-Lazenby group. The symbolic algebra module,
+array are available in Maple and Mathematica. The symbolic algebra module,
 :mod:`GA`, developed for python does not depend on an orthogonal basis
 representation, but rather is generated from a set of :math:`n` arbitrary
-symbolic vectors,  :math:`a_{1},a_{2},\dots,a_{n}` and a symbolic pseudo-metric
+symbolic vectors,  :math:`a_{1},a_{2},\dots,a_{n}` and a symbolic metric
 tensor :math:`g_{ij} = a_{i}\cdot a_{j}`.
 
 In order not to reinvent the wheel all scalar symbolic algebra is handled by the
@@ -97,7 +97,7 @@ python module  :mod:`sympy`.
 The basic geometic algebra operations will be implemented in python by defining
 a multivector  class, MV, and overloading the python operators in Table
 :ref:`1 <table1>` where ``A`` and ``B``  are any two multivectors (In the case of 
-``+``, ``-``, ``*``, ``^``, and ``|`` the operation is also defined if ``A`` or 
+``+``, ``-``, ``*``, ``^``, ``|``, ``<<``, and ``>>`` the operation is also defined if ``A`` or 
 ``B`` is a sympy symbol or a sympy real number).
 
 .. _table1:
@@ -111,14 +111,36 @@ a multivector  class, MV, and overloading the python operators in Table
 	" ``A*B`` ", " geometric product "  
 	" ``A^B`` ", " outer product of multivectors  "
 	" ``A|B`` ", " inner product of multivectors "
-	" ``A<B`` ", " left contraction of multivectors "
-	" ``A>B``  ", " right contraction of multivectors "
+	" ``A<B`` or ``A<<B`` ", " left contraction of multivectors "
+	" ``A>B`` or ``A>>B`` ", " right contraction of multivectors "
 
 Table :ref:`1 <table1>`. Multivector operations for symbolicGA
 
-Note that the operator order precedence is determined by python and is not
-neccessarily that used by  geometric algebra. Always use parenthesis in python
-expressions containing ``^``, ``|``, ``<``, and/or ``>``.
+The option to use ``<`` or ``<<`` for left contraction and ``>`` or ``>>`` is given since the ``<`` and
+``>`` operators do not have r-forms (there are no *__rlt__()* and *__rlt__()* functions to overload) while
+``<<`` and ``>>`` do have r-forms so that *x << A* and *x >> A* are allowed where *x* is a scalar (symbol or integer) 
+and *A* is a multivector. With ``<`` and ``>`` we can only have mixed modes (scalars and multivectors) if the 
+multivector is the first operand.
+
+.. note::
+
+    Except for ``<`` and ``>`` all the multivector operators have r-forms so that as long as one of the
+    operands, left or right, is a multivector the other can be a multivector or a scalar (sympy symbol or integer).
+
+.. warning::
+
+    Note that the operator order precedence is determined by python and is not
+    neccessarily that used by  geometric algebra. It is **absolutely essential** to 
+    use parenthesis in multivector
+    expressions containing ``^``, ``|``, ``<``, ``>``, ``<<`` and/or ``>>``.  As an example let
+    ``A`` and ``B`` be any two multivectors. Then ``A + A*B = A +(A*B)``, but
+    ``A+A^B = (2*A)^B`` since in python the ``^`` operator has a lower precedence
+    than the '+' operator.  In geometric algebra the outer and inner products and
+    the left and right contractions have a higher precedence than the geometric
+    product and the geometric product has a higher precedence than addition and
+    subtraction.  In python the ``^``, ``|``, ``<``, ``>``, ``<<`` and ``>>`` all have a lower
+    precedence than ``+`` and ``-`` while ``*`` has a higher precedence than
+    ``+`` and ``-``.
 
 
 .. _vbm:
@@ -127,7 +149,7 @@ Vector Basis and Metric
 =======================
 
 The two structures that define the :class:`MV` (multivector) class are the
-symbolic basis vectors and the  symbolic pseudometric.  The symbolic basis
+symbolic basis vectors and the  symbolic metric.  The symbolic basis
 vectors are input as a string with the symbol name separated by spaces.  For
 example if we are calculating the geometric algebra of a system with three
 vectors that we wish to denote as ``a0``, ``a1``, and ``a2`` we would define the
@@ -136,8 +158,8 @@ string variable:
 ``basis = 'a0 a1 a2'``
 
 that would be input into the multivector setup function.  The next step would be
-to define the symbolic  pseudometric for the geometric algebra of the basis we
-have defined. The default pseudometric is the most general and is the matrix of
+to define the symbolic  metric for the geometric algebra of the basis we
+have defined. The default metric is the most general and is the matrix of
 the following symbols
 
 .. _eq1:
@@ -244,7 +266,11 @@ purpose of output display, with strings that are concatenations of the strings
 representing the basis vectors.  So that in our example  ``[1,2]`` would be
 labeled with the string ``'a1a2'`` and represents the geometric product
 ``a1*a2``. Thus the list ``[0,1,2]`` represents ``a0*a1*a2``.For our example the
-complete set of bases and labels are shown in Table :ref:`2 <table2>` [#]_
+complete set of bases and labels are shown in Table :ref:`2 <table2>`
+
+.. note::
+
+	The empty list, ``[]``, represents the scalar 1.
 
 .. _table2:
 
@@ -418,6 +444,15 @@ and 1 for a blade representation.  One needs to keep track of which
 representation is in use since various multivector operations require conversion
 from one representation to the other.
 
+.. warning::
+
+    When the geometric product of two multivectors is calculated the module looks to 
+    see if either multivector is in blade representation.  If either is the result of
+    the geometric product is converted to a blade representation.  One result of this
+    is that if either of the multivectors is a simple vector (which is automatically a
+    blade) the result will be in a blade representation.  If ``a`` and ``b`` are vectors
+    then the result ``a*b`` will be ``(a.b)+a^b`` or simply ``a^b`` if ``(a.b) = 0``. 
+
 
 Outer and Inner Products, Left and Right Contractions
 =====================================================
@@ -547,9 +582,7 @@ The ``MV`` class function for the outer product of the multivectors ``mv1`` and
                             product.add_in_place(pg1pg2.project(igrade))
         return(product)
 
-In the  ``MV`` class we have overloaded the ``^`` operator so that instead of
-calling the function we can write ``mv1^ mv2``.  Due to the precedence rules for
-python we should ``always`` enclose outer and inner products in parenthesis.
+
 The steps for calculating the outer product are:
 
 #. Convert ``mv1`` and ``mv2`` to blade representation if they are not already
@@ -563,30 +596,71 @@ The steps for calculating the outer product are:
 
 #. Accumulate the results for each pair of grades in the input multivectors.
 
+.. warning::
+
+    In the  ``MV`` class we have overloaded the ``^`` operator to represent the outer 
+    product so that instead of calling the outer product function we can write ``mv1^ mv2``.
+    Due to the precedence rules for python it is **absolutely essential** to enclose outer products
+    in parenthesis.
+
 For the inner product of the multivectors ``mv1`` and ``mv2`` the ``MV`` class
 function is  ::
 
-   @staticmethod
-   def inner_product(mv1,mv2):
-       product = MV()
-       product.bladeflg = 1
-       mv1.convert_to_blades()
-       mv2.convert_to_blades()
-       for igrade1 in range(MV.n1):
-           if not isint(mv1.mv[igrade1]):
-               pg1 = mv1.project(igrade1)
-               for igrade2 in range(MV.n1):
-                   igrade = abs(igrade1-igrade2)
-                   if not isint(mv2.mv[igrade2]):
-                       pg2 = mv2.project(igrade2)
-                       pg1pg2 = pg1*pg2
-                       product.add_in_place(pg1pg2.project(igrade))
-       return(product) 
-
-In the ``MV`` class we have overloaded the ``|`` operator so that instead  of
-calling the function we can write ``mv1|mv2``. The inner product is calculated
-the same way  as the outer product except that in step 4, ``i1+i2`` is replaced
-by ``abs(i1-i2)``.
+    @staticmethod
+    def inner_product(mv1,mv2,mode='s'):
+        """
+        MV.inner_product(mv1,mv2) calculates the inner
+
+        mode = 's' - symmetic (Doran & Lasenby)
+        mode = 'l' - left contraction (Dorst)
+        mode = 'r' - right contraction (Dorst)
+        """
+        if isinstance(mv1,MV) and isinstance(mv2,MV):
+            product = MV()
+            product.bladeflg = 1
+            mv1.convert_to_blades()
+            mv2.convert_to_blades()
+            for igrade1 in range(MV.n1):
+                if isinstance(mv1.mv[igrade1],numpy.ndarray):
+                    pg1 = mv1.project(igrade1)
+                    for igrade2 in range(MV.n1):
+                        igrade = igrade1-igrade2
+                        if mode == 's':
+                            igrade = igrade.__abs__()
+                        else:
+                            if mode == 'l':
+                                igrade = -igrade
+                        if igrade >= 0:
+                            if isinstance(mv2.mv[igrade2],numpy.ndarray):
+                                pg2 = mv2.project(igrade2)
+                                pg1pg2 = pg1*pg2
+                                product.add_in_place(pg1pg2.project(igrade))
+            return(product)
+        else:
+            if mode == 's':
+                if isinstance(mv1,MV):
+                    product = mv1.scalar_mul(mv2)
+                if isinstance(mv2,MV):
+                    product = mv2.scalar_mul(mv1)
+            else:
+                product = None
+        return(product)
+
+
+The inner product is calculated the same way as the outer product except that in
+step 4, ``i1+i2`` is replaced by ``abs(i1-i2)`` or ``i1-i2`` for the right contraction or
+``i2-i1`` for the left contraction.  If ``i1-i2`` is less than zero there is no contribution
+to the right contraction.  If ``i2-i1`` is less than zero there is no contribution to the 
+left contraction. 
+
+.. warning::
+
+    In the ``MV`` class we have overloaded the ``|`` operator for the inner product,
+    ``>`` operator for the right contraction, and ``<`` operator for the left contraction.
+    Instead of calling the inner product function we can write ``mv1|mv2``, ``mv1>mv2``, or
+    ``mv1<mv2`` respectively for the inner product, right contraction, or left contraction.
+    Again, due to the precedence rules for python it is **absolutely essential** to enclose inner
+    products and/or contractions in parenthesis.
 
 
 .. _reverse:
@@ -1034,10 +1108,26 @@ curvilinear coordinates using:
 
    If ``str_mode=0`` the string representation of the multivector contains no
    newline characters (prints on one line).   If ``str_mode=1`` the string
+   representation of the multivector places a newline after each grade of the
+   multivector  (prints one grade per line).  If ``str_mode=2`` the string
    representation of the multivector places a newline after each base of the
-   multivector  (prints one base per line).  In both cases bases with zero
+   multivector  (prints one base per line). In both cases bases with zero
    coefficients are not printed.
 
+	.. note::
+
+		This function directly affects the way multivectors are printed with the
+		print command since it interacts with the :func:`__str__` function for the
+		multivector class which is used by the ``print`` command. 
+ 
+
+		.. csv-table:: 
+			:header: " ``str_mode`` ", " Effect on print " 
+			:widths: 10, 50
+
+			" 0 ","One multivector per line"
+			" 1 ","One grade per line"
+			" 2 ","One base per line"
 
 Instantiating a Multivector
 ---------------------------
@@ -1045,7 +1135,14 @@ Instantiating a Multivector
 Now that grades and bases have been described we can show all the ways that a
 multivector can be instantiated. As an example assume that the multivector space
 is initialized with ``MV.setup('e1 e2 e3')``. Then the vectors ``e1``, ``e2``,
-and ``e3`` are available for use in the program [#]_. So that  multivectors
+and ``e3`` are made available (broadcast) for use in the program . 
+
+.. warning::
+
+	This is only true if the statement  ``set_main(sys.modules[__name__])`` appears
+	immediately after the ``from sympy.galgebra.GA import *`` statement.
+
+So that  multivectors
 could be instantiated with statements such as (``a1``, ``a2``, and ``a3`` are
 ``sympy`` symbols)::
 
@@ -1071,8 +1168,9 @@ or with the multivector class constructor:
 		" default ", " default ", " Zero multivector "
 		" 'basisvector' ", " int i ", " :math:`\mbox{i}^{th}` basis vector "
 		" 'basisbivector' ", " int i ", " :math:`\mbox{i}^{th}` basis bivector "
-		" 'scalar' ", " symbol x ", " symbolic scalar of value x "
+		" 'scalar' ", " symbol x ", " symbolic scalar of value x"
 		"   ", " string s ", " symbolic scalar of value Symbol(s) "
+		"  ", " int i ", " sympy integer of value i"
 		" 'grade' ", " [int r, 1-D symbol array A] ", " X.grade(r) = A "
 		"   ", " [int r, string s] ", " symbolic grade r multivector "
 		" 'vector' ", " 1-D symbol array A ", " X.grade(1) = A "
@@ -1080,6 +1178,7 @@ or with the multivector class constructor:
 		" 'grade2' ", " 1-D symbol array A ", " X.grade(2) = A "
 		" 'pseudo' ", " symbol x ", " X.grade(n) = x "
 		" 'spinor' ", " string s ", " symbolic even multivector "
+		" default "," string s ", " symbolic general multivector "
 
 
    If the *value* argument has the option of being a string s then a general symbolic
@@ -1158,20 +1257,27 @@ Basic Multivector Class Functions
 
 .. function:: grad_ext(self)
 
-   Return the outer (curl) derivative of the multivector function.
+   Return the outer (curl) derivative of the multivector function. Equivalent to 
+   :func:`curl`.
 
 
 .. function:: grad_int(self)
 
-   Return the inner (div) derivative of the multivector function.
+   Return the inner (div) derivative of the multivector function. Equivalent to 
+   :func:`div`.
+
+.. warning::
 
+	If *A* is a vector field in three dimensions :math:`\nabla\cdot {\bf A}` = A.grad_int() = A.div(), but
+	:math:`\nabla\times {\bf A}` = -MV.I*A.grad_ext() = -MV.I*A.curl(). Note that grad_int() lowers the grade
+	of all blades by one grade and grad_ext() raises the grade of all blades by one.
 
 .. function:: set_coef(self,grade,base,value)
 
-   Set the multivector coefficient of index (*grade*,*base*) to *value*.
+   Set the multivector coefficient of index *(grade,base)* to *value*.
 
 
-Sumpy Functions Applied Inplace to Multivector Coefficients
+Sympy Functions Applied Inplace to Multivector Coefficients
 -----------------------------------------------------------
 
 All the following fuctions belong to the :class:`MV` class and apply the
@@ -1238,6 +1344,11 @@ class.
    Not only will *syms* contain the symbols, but you can also directly use *x*,
    *y*, and *ab* as symbols in your program.
 
+	.. warning::
+
+		You can only directly use *x*, *y*, and *ab* as symbols in your program if 
+		the statement  ``set_main(sys.modules[__name__])`` appears immediately after
+		the ``from sympy.galgebra.GA import *`` statement.
 
 .. function:: set_names(var_lst,var_str)
 
@@ -1620,10 +1731,4 @@ Div and Curl of Vector Function :math:`A`
       ``Geometric Algebra for Physicists`` by  C. Doran and A. Lasenby, Cambridge
       University Press, 2003.
 
-.. rubric:: Footnotes
-
-.. [#] The empty list, ``[]``, represents the scalar 1.
-
-.. [#] This is only true if the statement  ``set_main(sys.modules[__name__])`` appears
-   immediately after the ``from sympy import *`` statement.
 
diff --git a/sympy/galgebra/GA.py b/sympy/galgebra/GA.py
index 80a773d..ea7b3d0 100644
--- a/sympy/galgebra/GA.py
+++ b/sympy/galgebra/GA.py
@@ -730,13 +730,63 @@ class MV(object):
         return
 
     @staticmethod
-    def str_rep(mv,lst_mode=0):
-        """
-        Converts internal representation of a multivector to a string
-        for outputing.  If lst_mode = 1, str_rep outputs a list of
-        strings where each string contains one multivector coefficient
-        concatenated with the corressponding base or blade symbol.
+    def str_rep(mv):
+        """
+         Converts internal representation of a multivector to a string
+         for outputing.  If lst_mode = 1, str_rep outputs a list of
+         strings where each string contains one multivector coefficient
+         concatenated with the corresponding base or blade symbol.
+
+            MV.str_mode     Effect
+                0           Print entire multivector on one line (default)
+                1           Print each grade on a single line
+                2           Print each base on a single line
+         """
+ 
+        if MV.bladeprint:
+            mv.convert_to_blades()
+            labels = MV.bladelabel
+        else:
+            if not mv.bladeflg:
+                labels = MV.basislabel
+            else:
+                labels = MV.bladelabel
+        if isinstance(mv.mv[0],types.IntType):
+            value = ''
+        else:
+            value = (mv.mv[0][0]).__str__()
+        dummy = sympy.Symbol('dummy')
+        for igrade in MV.n1rg[1:]:            
+            if isinstance(mv.mv[igrade],numpy.ndarray):
+                j = 0
+                for x in mv.mv[igrade]:
+                    if x != ZERO:
+                        xstr = (x*dummy).__str__()
+                        if xstr[0] != '-' and len(value) > 0:
+                            xstr = '+'+xstr
+                        if xstr.find('dummy') < 2 and xstr[-5:] != 'dummy':
+                            xstr = xstr.replace('dummy*','')+'*'+labels[igrade][j]
+                        else:
+                            xstr = xstr.replace('dummy',labels[igrade][j])
+                        if MV.str_mode == 2:
+                            xstr += '\n'
+                        value += xstr
+                    j += 1
+                if MV.str_mode == 1:
+                    value += '\n'
+        if value == '':
+            value = '0'
+        value = value.replace(' ','')
+        return(value)
+
+    @staticmethod
+    def xstr_rep(mv,lst_mode=0):
         """
+         Converts internal representation of a multivector to a string
+         for outputing.  If lst_mode = 1, str_rep outputs a list of
+         strings where each string contains one multivector coefficient
+         concatenated with the corressponding base or blade symbol.
+         """
         if lst_mode:
             outlst = []
         if MV.bladeprint:
@@ -752,22 +802,23 @@ class MV(object):
             tmp = []
             if isinstance(mv.mv[igrade],numpy.ndarray):
                 j = 0
+                xsum = 0
                 for x in mv.mv[igrade]:
                     if x != ZERO:
                         xstr = x.__str__()
                         if xstr == '+1' or xstr == '1' or xstr == '-1':
-                            if xstr == '+1' or xstr == '1':
-                                xstr = '+'
-                            else:
-                                xstr = '-'
+                           if xstr == '+1' or xstr == '1':
+                               xstr = '+'
+                           else:
+                               xstr = '-'
                         else:
-                            if xstr[0] != '+':
-                                xstr = '+('+xstr+')'
-                            else:
-                                xstr = '+('+xstr[1:]+')'
+                           if xstr[0] != '+':
+                               xstr = '+('+xstr+')'
+                           else:
+                               xstr = '+('+xstr[1:]+')'
                         value += xstr+labels[igrade][j]
                         if MV.str_mode and not lst_mode:
-                            value += '\n'
+                            value += value+'\n'
                         if lst_mode:
                             tmp.append(value)
                     j += 1
@@ -1570,20 +1621,12 @@ class MV(object):
                     else:
                         if isinstance(mv2.mv[i],numpy.ndarray) and not isinstance(mv1.mv[i],numpy.ndarray):
                             sum.mv[i] = +mv2.mv[i]
+            return(sum)
         else:
             if isinstance(mv1,MV):
-                sum = mv1.copy()
-                if isinstance(sum.mv[0],numpy.ndarray):
-                    sum.mv[0] += numpy.array([mv2],dtype=numpy.object)
-                else:
-                    sum.mv[0] = numpy.array([mv2],dtype=numpy.object)
+                return(mv1+MV(mv2,'scalar')) 
             else:
-                sum = mv2.copy()
-                if isinstance(sum.mv[0],numpy.ndarray):
-                    sum.mv[0] += numpy.array([mv1],dtype=numpy.object)
-                else:
-                    sum.mv[0] = numpy.array([mv1],dtype=numpy.object)
-        return(sum)
+                return(MV(mv1,'scalar')+mv2)
 
     @staticmethod
     def subtraction(mv1,mv2):
@@ -1606,20 +1649,12 @@ class MV(object):
                     else:
                         if not isinstance(mv1.mv[i],numpy.ndarray) and isinstance(mv2.mv[i],numpy.ndarray):
                             diff.mv[i] = -mv2.mv[i]
+            return(diff)
         else:
             if isinstance(mv1,MV):
-                diff = mv1.copy()
-                if isinstandce(diff.mv[0],numpy.ndarray):
-                    diff.mv[0] -= numpy.array([mv2],dtype=numpy.object)
-                else:
-                    diff.mv[0] = -numpy.array([mv2],dtype=numpy.object)
+                return(mv1-MV(mv2,'scalar'))
             else:
-                diff = mv2.copy(1)
-                if isinstance(diff.mv[0],numpy.ndarray):
-                    diff.mv[0] += numpy.array([mv1],dtype=numpy.object)
-                else:
-                    diff.mv[0] = +numpy.array([mv1],dtype=numpy.object)
-        return(diff)
+                return(MV(mv1,'scalar')-mv2)
 
     @staticmethod
     def vdiff(vec,x):
@@ -1681,6 +1716,8 @@ class MV(object):
         if mvtype == 'scalar':
             if isinstance(value,types.StringType):
                 value = sympy.Symbol(value)
+            if isinstance(value,types.IntType):
+                value = sympy.Rational(value)
             self.mv[0] = numpy.array([value],dtype=numpy.object)
         if mvtype == 'pseudo':
             if isinstance(value,types.StringType):
@@ -1737,7 +1774,20 @@ class MV(object):
                             symbol_lst = make_symbols(symbol_str)
                             self.mv[grade] = numpy.array(symbol_lst,dtype=numpy.object)
                         else:
-                            self.mv[0] = numpy.array([value],dtype=numpy.object)
+                            self.mv[0] = numpy.array([sympy.Symbol(value)],dtype=numpy.object)
+                self.name = value+'bm'
+        if value != '' and mvtype == '': #Most general multivector
+            if isinstance(value,types.StringType):
+                for grade in MV.n1rg: 
+                    symbol_str = ''
+                    if grade != 0:
+                        for base in MV.basis[grade]:
+                            symbol = value+MV.construct_index(base)
+                            symbol_str += symbol+' '
+                        symbol_lst = make_symbols(symbol_str)
+                        self.mv[grade] = numpy.array(symbol_lst,dtype=numpy.object)
+                    else:
+                        self.mv[0] = numpy.array([sympy.Symbol(value)],dtype=numpy.object)
                 self.name = value+'bm'
         if fct and MV.coords != None:
             for grade in MV.n1rg:
@@ -1927,6 +1977,14 @@ class MV(object):
         """See MV.inner_product(self,mv)"""
         return(MV.inner_product(self,mv,'l'))
 
+    def __lshift__(self,mv):
+        """See MV.inner_product(self,mv)"""
+        return(MV.inner_product(self,mv,'l'))
+
+    def __rlshift__(self,mv):
+        """See MV.inner_product(self,mv)"""
+        return(MV.inner_product(mv,self,'l'))
+
     def lc(self,mv):
         return(MV.inner_product(self,mv,'l'))
 
@@ -1934,6 +1992,14 @@ class MV(object):
         """See MV.inner_product(self,mv)"""
         return(MV.inner_product(self,mv,'r'))
 
+    def __rshift__(self,mv):
+        """See MV.inner_product(self,mv)"""
+        return(MV.inner_product(self,mv,'r'))
+
+    def __rrshift__(self,mv):
+        """See MV.inner_product(self,mv)"""
+        return(MV.inner_product(mv,self,'r'))
+
     def rc(self,mv):
         return(MV.inner_product(self,mv,'r'))
 
@@ -1947,6 +2013,8 @@ class MV(object):
         mv.puregrade = self.puregrade
         for i in MV.n1rg:
             if isinstance(self.mv[i],numpy.ndarray):
+                #print self.mv[i]
+                #print c,type(c)
                 mv.mv[i] = self.mv[i]*c
         return(mv)
 
@@ -2403,6 +2471,9 @@ class MV(object):
                 igrade += 1
         return(dD)
 
+    def curl(self):
+        return(self.grad_ext())
+    
     def grad_int(self):
         """
         Calculate inner (interior,div) derivative of multivector function.
@@ -2427,6 +2498,9 @@ class MV(object):
                 igrade += 1
         return(dD)
 
+    def div(self):
+        return(self.grad_int())
+
     def mag2(self):
         """
         Calculate scalar component of square of multivector.
diff --git a/sympy/galgebra/examples/coords.py b/sympy/galgebra/examples/coords.py
index 9cb076e..bc18895 100755
--- a/sympy/galgebra/examples/coords.py
+++ b/sympy/galgebra/examples/coords.py
@@ -2,9 +2,6 @@
 #EandM.py
 
 import sys
-if sys.version.find('Stackless') >= 0:
-    sys.path.append('/usr/lib/python2.5/site-packages')
-
 import sympy.galgebra.GA as GA
 import sympy.galgebra.latex_ex as tex
 import sympy,numpy,time
@@ -16,8 +13,6 @@ if __name__ == '__main__':
              '0 1 0,'+\
              '0 0 1'
 
-    ti = time.time()
-
     GA.MV.setup('gamma_x gamma_y gamma_z',metric,True)
     tex.Format()
 
@@ -47,8 +42,4 @@ if __name__ == '__main__':
     tex.MV_format(3)
     print '-I\\lp\\nabla \\W A\\rp =',curlA
 
-    tf = time.time()
-
-    tex.xdvi(filename='coords.tex')
-
-    print 1000.0*(tf-ti)
+    tex.xdvi(filename='coords.tex')    
\ No newline at end of file
diff --git a/sympy/galgebra/tests/test_GA.py b/sympy/galgebra/tests/test_GA.py
index e7a8548..9fcc5b0 100644
--- a/sympy/galgebra/tests/test_GA.py
+++ b/sympy/galgebra/tests/test_GA.py
@@ -262,3 +262,12 @@ def test_derivative():
     assert (X*X*X).grad() == 5*X*X
     assert X.grad_int() == 3
 
+def test_str():
+    MV.setup('e_1 e_2 e_3','1 0 0, 0 1 0, 0 0 1')
+    
+    X = MV('x')
+    assert str(X) == 'x+x__0*e_1+x__1*e_2+x__2*e_3+x__01*e_1e_2+x__02*e_1e_3+x__12*e_2e_3+x__012*e_1e_2e_3'
+    Y = MV('y','spinor')
+    assert str(Y) == 'y+y__01*e_1e_2+y__02*e_1e_3+y__12*e_2e_3'
+    Z = X+Y
+    assert str(Z) == 'x+y+x__0*e_1+x__1*e_2+x__2*e_3+(x__01+y__01)*e_1e_2+(x__02+y__02)*e_1e_3+(x__12+y__12)*e_2e_3+x__012*e_1e_2e_3'
\ No newline at end of file
-- 
1.6.0.4

Reply via email to