/ doc / module-components.rst
module-components.rst
   1  Module Components
   2  =================
   3  
   4  .. math::
   5     \newcommand{\bm}[1]{\boldsymbol{#1}}
   6     \newcommand{\ubh}{\bm{\hat{u}}}
   7     \newcommand{\ebh}{\bm{\hat{e}}}
   8     \newcommand{\ebf}{\bm{e}}
   9     \newcommand{\mat}[1]{\left [ {#1} \right ]}
  10     \newcommand{\bra}[1]{{#1}_{\mathcal{G}}}
  11     \newcommand{\ket}[1]{{#1}_{\mathcal{D}}}
  12     \newcommand{\ds}{\displaystyle}
  13     \newcommand{\bfrac}[2]{\displaystyle\frac{#1}{#2}}
  14     \newcommand{\lp}{\left (}
  15     \newcommand{\rp}{\right )}
  16     \newcommand{\half}{\frac{1}{2}}
  17     \newcommand{\llt}{\left <}
  18     \newcommand{\rgt}{\right >}
  19     \newcommand{\abs}[1]{\left |{#1}\right |}
  20     \newcommand{\pdiff}[2]{\bfrac{\partial {#1}}{\partial {#2}}}
  21     \newcommand{\pdifftwo}[3]{\bfrac{\partial^{2} {#1}}{\partial {#2}\partial {#3}}}
  22     \newcommand{\lbrc}{\left \{}
  23     \newcommand{\rbrc}{\right \}}
  24     \newcommand{\set}[1]{\lbrc {#1} \rbrc}
  25     \newcommand{\W}{\wedge}
  26     \newcommand{\R}{\dagger}
  27     \newcommand{\lbrk}{\left [}
  28     \newcommand{\rbrk}{\right ]}
  29     \newcommand{\com}[1]{\lbrk {#1} \rbrk}
  30     \newcommand{\proj}[2]{\llt {#1} \rgt_{#2}}
  31     %\newcommand{\bm}{\boldsymbol}
  32     \newcommand{\braces}[1]{\left \{ {#1} \right \}}
  33     \newcommand{\grade}[1]{\left < {#1} \right >}
  34     \newcommand{\f}[2]{{#1}\lp {#2} \rp }
  35     \newcommand{\paren}[1]{\lp {#1} \rp }
  36     \newcommand{\eval}[2]{\left . {#1} \right |_{#2}}
  37     \newcommand{\prm}[1]{{#1}'}
  38     \newcommand{\ddt}[1]{\bfrac{d{#1}}{dt}}
  39     \newcommand{\deriv}[3]{\bfrac{d^{#3}#1}{d{#2}^{#3}}}
  40     \newcommand{\be}{\begin{equation}}
  41     \newcommand{\ee}{\end{equation}}
  42     \newcommand{\eb}{\bm{e}}
  43     \newcommand{\ehb}{\bm{\hat{e}}}
  44     \newcommand{\Tn}[2]{\f{\mathcal{T}_{#2}}{#1}}
  45     \newcommand{\tr}{\mbox{tr}}
  46     \newcommand{\T}[1]{\texttt{#1}}
  47     \newcommand{\grd}{\bm{\nabla}}
  48     \newcommand{\indices}[1]{#1}
  49     \newcommand{\xRightarrow}[1]{\overset{#1}{\Rightarrow}}
  50  
  51  .. currentmodule:: galgebra
  52  
  53  .. warning::
  54  
  55     This page is converted from the original :math:`\LaTeX` documentation, but
  56     may no longer reflect the current state of the library. See the API docs at
  57     :doc:`api` for more up-to-date but less structured and in-depth descriptions.
  58  
  59     If you would like to help with merging the descriptions on the API with a
  60     description on this page, please head over to :issue:`300` on GitHub, where
  61     there's an explanation of how to do so. Even merging just one function
  62     explanation helps!
  63  
  64     Any function or class below with a ``[source]`` link to its right is
  65     guaranteed to be up-to-date already, as its documentation is identical on
  66     both pages.
  67  
  68  The geometric algebra module consists of the following files and classes
  69  
  70  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  71  | File           | Classes                                    | Usage                                                                                                                                                |
  72  +================+============================================+======================================================================================================================================================+
  73  | ``metric.py``  | :class:`~galgebra.metric.Metric`           | Instantiates metric tensor and derivatives of basis vectors. Normalized basis if required.                                                           |
  74  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  75  | ``ga.py``      | :class:`~galgebra.ga.Ga`                   | Instantiates geometric algebra (inherits :class:`~galgebra.metric.Metric`), generates bases, blades, multiplication tables, reciprocal basis, and    |
  76  |                |                                            | left and right geometric derivative operators.                                                                                                       |
  77  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  78  |                | :class:`~galgebra.ga.Sm`                   | Instantiates geometric algebra for submainfold (inherits :class:`~galgebra.ga.Ga`).                                                                  |
  79  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  80  | ``mv.py``      | :class:`~galgebra.mv.Mv`                   | Instantiates multivector.                                                                                                                            |
  81  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  82  |                | :class:`~galgebra.mv.Dop`                  | Instantiates linear multivector differential operator.                                                                                               |
  83  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  84  | ``lt.py``      | :class:`~galgebra.lt.Lt`                   | Instantiates multivector linear transformation.                                                                                                      |
  85  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  86  | ``printer.py`` | :class:`~galgebra.printer.Eprint`          | Starts enhanced text printing on ANSI terminal (requires ``ConEmu`` on Windows).                                                                     |
  87  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  88  |                | :class:`~galgebra.printer.GaPrinter`       | Text printer for all geometric algebra classes (inherits from :class:`sympy.printing.str.StrPrinter`).                                               |
  89  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  90  |                | :class:`~galgebra.printer.GaLatexPrinter`  | :math:`\LaTeX`\ printer for all geometric algebra classes (inherits from :class:`sympy.printing.latex.LatexPrinter`).                                |
  91  +----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
  92  
  93  Instantiating a Geometric Algebra
  94  ---------------------------------
  95  
  96  The geometric algebra class is instantiated with
  97  
  98  .. class:: galgebra.ga.Ga(basis, g=None, coords=None, X=None, norm=False, sig='e', Isq='-', wedge=True, debug=False)
  99     :noindex:
 100  
 101     The ``basis`` and ``g`` parameters were described in section :ref:`BasisMetric`. If the metric is a function of position, if we have multivector fields, or we wish to calculate geometric derivatives a coordinate set, ``coords``, is required. ``coords`` is a list of *sympy* symbols. For the case of instantiating a 3-d geometric algebra in spherical coordinates we have
 102  
 103     .. code:: python
 104  
 105        r, th, phi = coords = symbols('r,theta,phi', real=True)
 106        basis = 'e_r e_theta e_phi'
 107        g = [1, r**2, r**2*sin(th)**2]
 108        sp3d = Ga(basis, g=g, coords=coords, norm=True)
 109  
 110     The input ``X`` allows the metric to be input as a vector manifold. ``X`` is a list of functions of ``coords`` of dimension, :math:`m`, equal to or greater than the number of coordinates. If ``g=None`` it is assumed that ``X`` is a vector in an :math:`m`-dimensional orthonormal Euclidean vector space. If it is wished the embedding vector space to be non-Euclidean that condition is specified with ``g``. For example if we wish the embedding space to be a 5-dimensional Minkowski space then
 111     ``g=[-1, 1, 1, 1, 1]``. Then the Ga class uses ``X`` to calculate the manifold basis vectors as a function of the coordinates and from them the metric tensor\ [12]_.
 112  
 113     If ``norm=True`` the basis vectors of the manifold are normalized so that the absolute values of the squares of the basis vectors are one. *Currently you should only use this option for diagonal metric tensors, and even there due so with caution, due to the possible problems with taking the square root of a general*\ sympy\* expression (one that has an unknown sign).\*
 114  
 115     **When a geometric algebra is created the unnormalized metric tensor is always saved so that submanifolds created from the normalized manifold can be calculated correctly.**
 116  
 117     ``sig`` indicates the signature of the vector space in the following ways\ [13]_.
 118  
 119     1. If the metric tensor is purely numerical (the components are not symbolic or functions of the coordinates) and is diagonal (orthogonal basis vectors) the signature is computed from the metric tensor.
 120  
 121     2. If the metric tensor is not purely numerical and orthogonal the following hints are used (dimension of vector space is :math:`n`)
 122  
 123        1. ``sig='e'`` the default hint assumes the signature is for a Euclidean space with signature :math:`(n,0)`.
 124  
 125        2. ``sig='m+'`` assumes the signature if for the Minkowski space :math:`(n-1,1)`.
 126  
 127        3. ``sig='m-'`` assumes the signature if for the Minkowski space :math:`(1,n-1)`.
 128  
 129        4. ``sig=p`` where ``p`` is an integer :math:`p\le n` and the signature it :math:`(p,n-p)`.
 130  
 131     If the metric tensor contains no symbolic constants, but is a function of the coordinates, it is possible to determine the signature of the metric numerically by specifying a allowed numerical coordinate tuple due to the invariance of the signature. This will be implemented in the future.
 132  
 133     Currently one need not be concerned about inputting ``sig`` unless one in using the *Ga* member function ``Ga.I()`` or the functions ``Mv.dual()`` or ``cross()`` which also use ``Ga.I()``.
 134  
 135     If :math:`I^{2}` is numeric it is calculated if it is not numeric then ``Isq='-'`` is the sign of the square of the pseudo-scalar. This is needed for some operations. The default is chosen for the case of a general 3D Euclidean metric.
 136  
 137     If ``wedge=True`` the basis blades of a multivector are printed using the ``^`` symbol between basis vectors. If ``wedge=False`` the subscripts of each individual basis vector (assuming that the basis vector symbols are of the form root symbol with a subscript\ [14]_). For example in three dimensions if the basis vectors are :math:`{{\eb}}_{x}`, :math:`{{\eb}}_{y}`, and :math:`{{\eb}}_{z}` the grade 3 basis blade would be printed as :math:`{{\eb}}_{xyz}`.
 138  
 139     If ``debug=True`` the data structures required to initialize the Ga class are printed out.
 140  
 141     To get the basis vectors for ``sp3d`` we would have to use the member function ``Ga.mv()`` in the form
 142  
 143     .. code:: python
 144  
 145        er, eth, ephi = sp3d.mv()
 146  
 147  To access the reciprocal basis vectors of the geometric algebra use the member function ``mvr()``
 148  
 149  .. method:: galgebra.ga.Ga.mvr(norm='True')
 150     :noindex:
 151  
 152     ``Ga.mvr(norm)`` returns the reciprocal basis vectors as a tuple. This allows the programmer to attach any python variable names to the reciprocal basis vectors that is convenient. For example (demonstrating the use of both ``mv()`` and ``mvr()``)
 153  
 154     .. code:: python
 155  
 156        e_x, e_y, e_z = o3d.mv()
 157        e__x, e__y, e__z = o3d.mvr()
 158  
 159     If ``norm='True'`` or the basis vectors are orthogonal the dot product of the basis vector and the corresponding reciprocal basis vector is one :math:`{\lp {e_{i}\cdot e^{j}=\delta_{i}^{j}} \rp }`. If ``norm='False'`` and the basis is non-orthogonal The dot product of the basis vector and the corresponding reciprocal basis vector is the square of the pseudo scalar, :math:`I^{2}`, of the geometric algebra :math:`{\lp {e_{i}\cdot e^{j}=E^{2}\delta_{i}^{j}} \rp }`.
 160  
 161  In addition to the basis vectors, if coordinates are defined for the geometric algebra, the left and right geometric derivative operators are calculated and accessed with the ``Ga`` member function ``grads()``.
 162  
 163  .. method:: galgebra.ga.Ga.grads()
 164     :noindex:
 165  
 166     ``Ga.grads()`` returns a tuple with the left and right geometric derivative operators. A typical usage would be
 167  
 168     .. code:: python
 169  
 170        grad, rgrad = sp3d.grads()
 171  
 172     for the spherical 3-d geometric algebra. The left derivative :math:`{\lp {{\texttt{grad}} ={\boldsymbol{\nabla}}} \rp }` and the right derivative :math:`{\lp {{\texttt{rgrad}} = {\boldsymbol{\bar{\nabla}}}} \rp }` have been explained in section :ref:`ldops`. Again the names ``grad`` and ``rgrad`` used in a program are whatever the user chooses them to be. In the previous example ``grad`` and ``rgrad`` are used.
 173  
 174  an alternative instantiation method is
 175  
 176  .. method:: galgebra.ga.Ga.build(basis, g=None, coords=None, X=None, norm=False, debug=False)
 177     :noindex:
 178  
 179     The input parameters for ``Ga.build()`` are the same as for ``Ga()``. The difference is that in addition to returning the geometric algebra ``Ga.build()`` returns the basis vectors at the same time. Using ``Ga.build()`` in the previous example gives
 180  
 181     .. code:: python
 182  
 183        r, th, phi = coords = symbols('r,theta,phi', real=True)
 184        basis = 'e_r e_theta e_phi'
 185        g = [1, r**2, r**2*sin(th)**2]
 186        sp3d, er, eth, ephi = Ga.build(basis, g=g, coord=coords, norm=True)
 187  
 188  To access the pseudo scalar of the geometric algebra use the member function ``I()``.
 189  
 190  .. method:: galgebra.ga.Ga.I()
 191     :noindex:
 192  
 193     ``Ga.I()`` returns the normalized pseudo scalar :math:`{\lp {{\left |{I^{2}}\right |}=1} \rp }` for the geometric algebra. For example :math:`I = \mbox{{\texttt{o3d.I()}}}` for the ``o3d`` geometric algebra. This function requires the signature of the vector space (see instantiating a geometric algebra).
 194  
 195  .. method:: galgebra.ga.Ga.E()
 196     :noindex:
 197  
 198     ``Ga.E()`` returns the unnormalized pseudo scalar :math:`E_{n} = {\eb}_{1}{\wedge}\dots{\wedge}{\eb}_{n}` for the geometric algebra.
 199  
 200  In general we have defined member functions of the ``Ga`` class that will instantiate objects of other classes since the objects of the other classes are all associated with a particular geometric algebra object. Thus we have
 201  
 202  ===================== ========================= ===========================
 203  Object                Class                     ``Ga`` method
 204  ===================== ========================= ===========================
 205  multivector           :class:`~galgebra.mv.Mv`  :meth:`~galgebra.ga.Ga.mv`
 206  submanifold           :class:`~galgebra.ga.Sm`  :meth:`~galgebra.ga.Ga.sm`
 207  linear transformation :class:`~galgebra.lt.Lt`  :meth:`~galgebra.ga.Ga.lt`
 208  differential operator :class:`~galgebra.mv.Dop` :meth:`~galgebra.ga.Ga.dop`
 209  ===================== ========================= ===========================
 210  
 211  for the instantiation of various objects from the ``Ga`` class. This means that in order to instantiate any of these objects we need only to import ``Ga`` into our program.
 212  
 213  .. _makeMV:
 214  
 215  Instantiating a Multivector
 216  ---------------------------
 217  
 218  Since we need to associate each multivector with the geometric algebra that contains it we use a member function of Ga to instantiate every multivector\ [15]_ The multivector is instantiated with:
 219  
 220  .. method:: galgebra.ga.Ga.mv(name, mode, f=False)
 221     :noindex:
 222  
 223     As an example of both instantiating a geometric algebra and multivectors consider the following code fragment for a 3-d Euclidean geometric algebra.
 224  
 225     .. code:: python
 226  
 227        from sympy import symbols
 228        from ga import Ga
 229        x, y, z = coords = symbols('x,y,z',real=True)
 230        o3d = Ga('e_x e_y e_z', g=[1, 1, 1], coords=coords)
 231        ex, ey, ez = o3d.mv()
 232        V = o3d.mv('V', 'vector', f=True)
 233        f = o3d.mv(x*y*z)
 234        B = o3d.mv('B', 2)
 235  
 236     First consider the multivector instantiation in line 6,
 237  
 238     ``V = o3d.mv('V','vector',f=True)``
 239  
 240     .Here a 3-dimensional multivector field that is a function of ``x``, ``y``, and ``z`` (``f=True``) is being instantiated. If latex output were used (to be discussed later) the multivector ``V`` would be displayed as
 241  
 242     .. math:: \be V^{x}\eb_{x} + V^{y}\eb_{y} + V^{z}\eb_{z} \ee
 243  
 244     Where the coefficients of the basis vectors are generalized *sympy* functions of the coordinates. If ``f=(x,y)`` then the coefficients would be functions of ``x`` and ``y``. In general is ``f`` is a tuple of symbols then the coefficients of the basis would be functions of those symbols. The superscripts\ [16]_ are formed from the coordinate symbols or if there are no coordinates from the subscripts of the basis vectors. The types of name and modes available for multivector instantiation are
 245  
 246     ======== ========================== ===============================================
 247     ``name`` ``mode``                   result
 248     ======== ========================== ===============================================
 249     string s ``scalar``                 symbolic scalar of value Symbol(s)
 250     string s ``vector``                 symbolic vector
 251     string s ``grade2`` or ``bivector`` symbolic bivector
 252     string s ``r`` (integer)            symbolic r-grade multivector
 253     string s ``pseudo``                 symbolic pseudoscalar
 254     string s ``spinor``                 symbolic even multivector
 255     string s ``mv``                     symbolic general multivector
 256     scalar c None                       zero grade multivector with coefficient value c
 257     ======== ========================== ===============================================
 258  
 259     Line 5 of the previous listing illustrates the case of using the ``mv`` member function with no arguments. The code does not return a multivector, but rather a tuple or the basis vectors of the geometric algebra ``o3d``. The elements of the tuple then can be used to construct multivectors, or multivector fields through the operations of addition, subtraction, multiplication (geometric, inner, and outer products and left and right contraction). As an example we could construct the vector
 260     function
 261  
 262     .. code:: python
 263  
 264        F = x**2*ex + z*ey + x*y*ez
 265  
 266     or the bivector function
 267  
 268     .. code:: python
 269  
 270        B = z*(ex^ey) + y*(ey^ez) + y*(ex^ez).
 271  
 272     Line 7 is an example of instantiating a multivector scalar function (a multivector with only a scalar part). If we print ``f`` the result is ``x*y*z``. Line 8 is an example of instantiating a grade :math:`r` (in the example a grade 2) multivector where
 273  
 274     .. math:: \be B = B^{xy}{\eb}_{x}{\wedge}{\eb}_{y}+B^{yz}{\eb}_{y}{\wedge}{\eb}_{z}+B^{xz}{\eb}_{x}{\wedge}{\eb}_{z}. \ee
 275  
 276  If one wished to calculate the left and right geometric derivatives of ``F`` and ``B`` the required code would be
 277  
 278  .. code:: python
 279  
 280     grad, rgrad = o3d.grads()
 281     dF = grad*F
 282     dB = grad*B
 283     dFr = F*rgrad
 284     dBr = B*rgrad
 285  
 286  ``dF``, ``dB``, ``dFr``, and ``dBr`` are all multivector functions. For the code where the order of the operations are reversed
 287  
 288  .. code:: python
 289  
 290     grad, rgrad = o3d.grads()
 291     dFop = F*grad
 292     dBop = B*grad
 293     dFrop = rgrad*F
 294     dBrop = rgrad*B
 295  
 296  ``dFop``, ``dBop``, ``dFrop``, and ``dBrop`` are all multivector differential operators (again see section :ref:`ldops`).
 297  
 298  Backward Compatibility Class MV
 299  -------------------------------
 300  
 301  In order to be backward compatible with older versions of *galgebra* we introduce the class :class:`~galgebra.deprecated.MV` which is inherits it’s functions from then class Mv. To instantiate a geometric algebra using MV use the static function
 302  
 303  .. automethod:: galgebra.deprecated.MV.setup
 304     :noindex:
 305  
 306  .. class:: galgebra.deprecated.MV(base, mvtype, fct=False, blade_rep=True)
 307     :noindex:
 308  
 309     For the instantiation of multivector using ``MV`` the ``base`` and ``mvtype`` arguments are the same as for new methods of multivector instantiation. The ``fct`` input is the same and the ``g`` input in the new methods. ``blade_rep`` is not used in the new methods so setting ``blade_rep=False`` will do nothing. Effectively ``blade_rep=False`` was not used in the old examples.
 310  
 311  .. automethod:: galgebra.deprecated.MV.Fmt
 312     :noindex:
 313  
 314  Basic Multivector Class Functions
 315  ---------------------------------
 316  
 317  If we can instantiate multivectors we can use all the multivector class functions as described as follows.
 318  
 319  .. method:: galgebra.mv.Mv.blade_coefs(basis_lst)
 320     :noindex:
 321  
 322     Find coefficients (sympy expressions) of multivector basis blade expansion corresponding to basis blades in ``basis_lst``. For example if :math:`V = V^{x}{{\eb}}_{x}+V^{y}{{\eb}}_{x}+V^{z}{{\eb}}_{x}` Then :math:`V\text{.blade_coefs}([{{\eb}}_{z},{{\eb}}_{x}]) = [V^{z},V^{x}]` or if :math:`B = B^{xy}{{\eb}}_{x}{\wedge}{{\eb}}_{y}+V^{yz}{{\eb}}_{y}{\wedge}{{\eb}}_{z}` then :math:`B\text{.blade_coefs}([{{\eb}}_{x}{\wedge}{{\eb}}_{y}]) = [B^{xy}]`.
 323  
 324  .. method:: galgebra.mv.Mv.convert_to_blades()
 325     :noindex:
 326  
 327     Convert multivector from the base representation to the blade representation. If multivector is already in blade representation nothing is done.
 328  
 329  .. method:: galgebra.mv.Mv.convert_from_blades()
 330     :noindex:
 331  
 332     Convert multivector from the blade representation to the base representation. If multivector is already in base representation nothing is done.
 333  
 334  .. method:: galgebra.mv.Mv.diff(var)
 335     :noindex:
 336  
 337     Calculate derivative of each multivector coefficient with respect to variable ``var`` and form new multivector from coefficients.
 338  
 339  .. method:: galgebra.mv.Mv.dual()
 340     :noindex:
 341  
 342     The mode of the ``dual()`` function is set by the ``Ga`` class static member function, ``GA.dual_mode(mode='I+')`` of the ``GA`` geometric galgebra which sets the following return values (:math:`I` is the pseudo-scalar for the geometric algebra ``GA``)
 343  
 344     =========== ================
 345     ``mode``    Return Value
 346     =========== ================
 347     ``'+I'``    :math:`IA`
 348     ``'I+'``    :math:`AI`
 349     ``'-I'``    :math:`-IA`
 350     ``'I-'``    :math:`-AI`
 351     ``'+Iinv'`` :math:`I^{-1}A`
 352     ``'Iinv+'`` :math:`AI^{-1}`
 353     ``'-Iinv'`` :math:`-I^{-1}A`
 354     ``'Iinv-'`` :math:`-AI^{-1}`
 355     =========== ================
 356  
 357     For example if the geometric algebra is ``o3d``, ``A`` is a multivector in ``o3d``, and we wish to use ``mode='I-'``. We set the mode with the function ``o3d.dual('I-')`` and get the dual of ``A`` with the function ``A.dual()`` which returns :math:`-AI`.
 358  
 359     If ``o3d.dual(mode)`` is not called the default for the dual mode is ``mode='I+'`` and ``A*I`` is returned.
 360  
 361     Note that ``Ga.dual(mode)`` used the function ``Ga.I()`` to calculate the normalized pseudoscalar. Thus if the metric tensor is not numerical and orthogonal the correct hint for then ``sig`` input of the *Ga* constructor is required.
 362  
 363  .. method:: galgebra.mv.Mv.even()
 364     :noindex:
 365  
 366     Return the even grade components of the multivector.
 367  
 368  .. method:: galgebra.mv.Mv.exp(hint='-')
 369     :noindex:
 370  
 371     If :math:`A` is a multivector then :math:`e^{A}` is defined for any :math:`A` via the series expansion for :math:`e`. However as a practical matter we only have a simple closed form formula for :math:`e^{A}` if :math:`A^{2}` is a scalar\ [18]_. If :math:`A^{2}` is a scalar and we know the sign of :math:`A^{2}` we have the following formulas for :math:`e^{A}`.
 372  
 373     .. math::
 374  
 375        $\begin{aligned}
 376        A^{2} > 0 : & & &\\
 377        A &= \sqrt{A^{2}} {\displaystyle\frac{A}{\sqrt{A^{2}}}} ,& e^{A} &= {{\cosh}\lp {\sqrt{A^{2}}} \rp }+{{\sinh}\lp {\sqrt{A^{2}}} \rp }{\displaystyle\frac{A}{\sqrt{A^{2}}}} \\
 378        A^{2} < 0 : & & &\\
 379        A &= \sqrt{-A^{2}} {\displaystyle\frac{A}{\sqrt{-A^{2}}}} ,& e^{A} &= {{\cos}\lp {\sqrt{-A^{2}}} \rp }+{{\sin}\lp {\sqrt{-A^{2}}} \rp }{\displaystyle\frac{A}{\sqrt{-A^{2}}}} \\
 380        A^{2} = 0 : & & &\\
 381        A &=0 ,& e^{A} &= 1 + A
 382        \end{aligned}
 383  
 384     The hint is required for symbolic multivectors :math:`A` since in general *sympy* cannot determine if :math:`A^{2}` is positive or negative. If :math:`A` is purely numeric the hint is ignored since the sign can be calculated.
 385  
 386  .. method:: galgebra.mv.Mv.expand()
 387     :noindex:
 388  
 389     Return multivector in which each coefficient has been expanded using *sympy* ``expand()`` function.
 390  
 391  .. method:: galgebra.mv.Mv.factor()
 392     :noindex:
 393  
 394     Apply the ``sympy`` ``factor`` function to each coefficient of the multivector.
 395  
 396  .. method:: galgebra.mv.Mv.Fmt(fmt=1, title=None)
 397     :noindex:
 398  
 399     Fuction to print multivectors in different formats where
 400  
 401     ======= ============================================
 402     ``fmt``
 403     ======= ============================================
 404     1       Print entire multivector on one line.
 405     2       Print each grade of multivector on one line.
 406     3       Print each base of multivector on one line.
 407     ======= ============================================
 408  
 409     ``title`` appends a title string to the beginning of the output. An equal sign in the title string is not required, but is added as a default. Note that ``Fmt`` only overrides the the global multivector printing format for the particular instance being printed. To reset the global multivector printing format use the function :func:`~galgebra.printer.Fmt` in the :mod:`galgebra.printer` module.
 410  
 411  .. method:: galgebra.mv.Mv.func(fct)
 412     :noindex:
 413  
 414     Apply the ``sympy`` scalar function ``fct`` to each coefficient of the multivector.
 415  
 416  .. method:: galgebra.mv.Mv.grade(igrade=0)
 417     :noindex:
 418  
 419     Return a multivector that consists of the part of the multivector of grade equal to ``igrade``. If the multivector has no ``igrade`` part return a zero multivector.
 420  
 421  .. method:: galgebra.mv.Mv.inv()
 422     :noindex:
 423  
 424     Return the inverse of the multivector :math:`M` (``M.inv()``). If :math:`M` is a non-zero scalar return :math:`1/M`. If :math:`M^{2}` is a non-zero scalar return :math:`M/{\lp {M^{2}} \rp }`, If :math:`MM^{{\dagger}}` is a non-zero scalar return :math:`M^{{\dagger}}/{\lp {MM^{{\dagger}}} \rp }`. Otherwise exit the program with an error message.
 425  
 426     All division operators (``/``, ``/=``) use right multiplication by the inverse.
 427  
 428  .. method:: galgebra.mv.Mv.norm(hint='+')
 429     :noindex:
 430  
 431     Return the norm of the multivector :math:`M` (``M.norm()``) defined by :math:`\sqrt{{\left |{MM^{{\dagger}}}\right |}}`. If :math:`MM^{{\dagger}}` is a scalar (a *sympy* scalar is returned). If :math:`MM^{{\dagger}}` is not a scalar the program exits with an error message. If :math:`MM^{{\dagger}}` is a number *sympy* can determine if it is positive or negative and calculate the absolute value. If :math:`MM^{{\dagger}}` is a *sympy* expression (function) *sympy* cannot determine the sign of
 432     the expression so that ``hint='+'`` or ``hint='-'`` is needed to determine if the program should calculate :math:`\sqrt{MM^{{\dagger}}}` or :math:`\sqrt{-MM^{{\dagger}}}`. For example if we are in a Euclidean space and ``M`` is a vector then ``hint='+'``, if ``M`` is a bivector then let ``hint='-'``. If ``hint='0'`` and :math:`MM^{{\dagger}}` is a symbolic scalar ``sqrt(Abs(M*M.rev()))`` is returned where ``Abs()`` is the *sympy* symbolic absolute value function.
 433  
 434  .. method:: galgebra.mv.Mv.norm2()
 435     :noindex:
 436  
 437     Return the the scalar defined by :math:`MM^{{\dagger}}` if :math:`MM^{{\dagger}}` is a scalar. If :math:`MM^{{\dagger}}` is not a scalar the program exits with an error message.
 438  
 439  .. method:: galgebra.mv.Mv.proj(bases_lst)
 440     :noindex:
 441  
 442     Return the projection of the multivector :math:`M` (``M.proj(bases_lst)``) onto the subspace defined by the list of bases (``bases_lst``).
 443  
 444  .. method:: galgebra.mv.Mv.proj(lst)
 445     :noindex:
 446  
 447     Return the projection of the mutivector :math:`A` onto the list, :math:`lst`, of basis blades. For example if :math:`A = A^{x}{{\eb}}_{x}+A^{y}{{\eb}}_{y}+A^{z}{{\eb}}_{z}` then :math:`A.proj{\lp {[{{\eb}}_{x},{{\eb}}_{y}]} \rp } = A^{x}{{\eb}}_{x}+A^{y}{{\eb}}_{y}`. Similarly if :math:`A = A^{xy}{{\eb}}_{x}{\wedge}{{\eb}}_{y}+A^{yz}{{\eb}}_{y}{\wedge}{{\eb}}_{z}` then :math:`A.proj{\lp {[{{\eb}}_{x}{\wedge}{{\eb}}_{y}]} \rp } = A^{xy}{{\eb}}_{x}{\wedge}{{\eb}}_{y}`.
 448  
 449  .. method:: galgebra.mv.Mv.project_in_blade(blade)
 450     :noindex:
 451  
 452     Return the projection of the mutivector :math:`A` in subspace defined by the blade, :math:`B`, using the formula :math:`{\lp {A\rfloor B} \rp }B^{-1}` in :cite:`Macdonald1`, page 121.
 453  
 454  .. method:: galgebra.mv.Mv.pure_grade()
 455     :noindex:
 456  
 457     If the multivector :math:`A` is pure (only contains one grade) return, :math:`A.pure\_grade()`, the index ('0' for a scalar, '1' for vector, '2' for a bi-vector, etc.) of the non-zero grade. If :math:`A` is not pure return the negative of the highest non-zero grade index.
 458  
 459  .. method:: galgebra.mv.Mv.odd()
 460     :noindex:
 461  
 462     Return odd part of multivector.
 463  
 464  .. method:: galgebra.mv.Mv.reflect_in_blade(blade)
 465     :noindex:
 466  
 467     Return the reflection of the mutivector :math:`A` in the subspace defined by the :math:`r`-grade blade, :math:`B_{r}`, using the formula (extended to multivectors) :math:`\sum_{i} {\lp {-1} \rp }^{r{\lp {i+1} \rp }}{B}_{r}{\left < {A} \right >}_{i}B_{r}^{-1}` in :cite:`Macdonald1`, page 129.
 468  
 469  .. method:: galgebra.mv.Mv.rev()
 470     :noindex:
 471  
 472     Return the reverse of the multivector.
 473  
 474  .. method:: galgebra.mv.Mv.rotate_multivector(itheta, hint='-')
 475     :noindex:
 476  
 477     Rotate the multivector :math:`A` via the operation :math:`e^{-\theta i/2}Ae^{\theta i/2}` where itheta = :math:`\theta i`, :math:`\theta` is a scalar, and :math:`i` is a unit, :math:`i^{2} = \pm 1`, 2-blade. If :math:`{\lp {\theta i} \rp }^{2}` is not a number ``hint`` is required to determine the sign of the square of ``itheta``. The default chosen, ``hint='-'``, is correct for any Euclidean space.
 478  
 479  .. method:: galgebra.mv.Mv.scalar()
 480     :noindex:
 481  
 482     Return the coefficient (*sympy* scalar) of the scalar part of a multivector.
 483  
 484  .. method:: galgebra.mv.Mv.simplify(mode=simplify)
 485     :noindex:
 486  
 487     ``mode`` is a *sympy* simplification function of a list/tuple of *sympy* simplification functions that are applied in sequence (if more than one function) each coefficient of the multivector. For example if we wished to applied ``trigsimp`` and ``ratsimp`` *sympy* functions to the multivector ``F`` the code would be
 488  
 489     .. code:: python
 490  
 491        Fsimp = F.simplify(mode=[trigsimp, ratsimp]).
 492  
 493     Actually ``simplify`` could be used to apply any scalar *sympy* function to the coefficients of the multivector.
 494  
 495  .. method:: galgebra.mv.Mv.set_coef(grade, base, value)
 496     :noindex:
 497  
 498     Set the multivector coefficient of index ``(grade, base)`` to ``value``.
 499  
 500  .. method:: galgebra.mv.Mv.subs(x)
 501     :noindex:
 502  
 503     Return multivector where *sympy* subs function has been applied to each coefficient of multivector for argument dictionary/list ``x``.
 504  
 505  .. method:: galgebra.mv.Mv.trigsimp(**kwargs)
 506     :noindex:
 507  
 508     Apply the ``sympy`` trigonometric simplification function ``trigsimp`` to each coefficient of the multivector. ``**kwargs`` are the arguments of trigsimp. See ``sympy`` documentation on ``trigsimp`` for more information.
 509  
 510  Basic Multivector Functions
 511  ---------------------------
 512  
 513  .. automethod:: galgebra.ga.Ga.com
 514     :noindex:
 515  
 516  .. autofunction:: galgebra.mv.cross
 517     :noindex:
 518  
 519  .. autofunction:: galgebra.printer.def_prec
 520     :noindex:
 521  
 522  .. autofunction:: galgebra.mv.dual
 523     :noindex:
 524  
 525  .. autofunction:: galgebra.mv.even
 526     :noindex:
 527  
 528  .. autofunction:: galgebra.mv.exp
 529     :noindex:
 530  
 531  .. autofunction:: galgebra.printer.GAeval
 532     :noindex:
 533  
 534  .. autofunction:: galgebra.mv.grade
 535     :noindex:
 536  
 537  .. autofunction:: galgebra.mv.inv
 538     :noindex:
 539  
 540  .. autofunction:: galgebra.mv.Nga
 541     :noindex:
 542  
 543  .. autofunction:: galgebra.mv.norm
 544     :noindex:
 545  
 546  .. autofunction:: galgebra.mv.norm2
 547     :noindex:
 548  
 549  .. autofunction:: galgebra.mv.odd
 550     :noindex:
 551  
 552  .. autofunction:: galgebra.mv.proj
 553     :noindex:
 554  
 555  .. automethod:: galgebra.ga.Ga.ReciprocalFrame
 556     :noindex:
 557  
 558  .. autofunction:: galgebra.mv.refl
 559     :noindex:
 560  
 561  .. autofunction:: galgebra.mv.rev
 562     :noindex:
 563  
 564  .. autofunction:: galgebra.mv.rot
 565     :noindex:
 566  
 567  .. _makeMVD:
 568  
 569  Multivector Derivatives
 570  -----------------------
 571  
 572  The various derivatives of a multivector function is accomplished by multiplying the gradient operator vector with the function. The gradient operation vector is returned by the ``Ga.grads()`` function if coordinates are defined. For example if we have for a 3-D vector space
 573  
 574  .. code:: python
 575  
 576     X = x, y, z = symbols('x y z')
 577     o3d = Ga('e*x|y|z', metric=[1, 1, 1], coords=X)
 578     ex, ey, ez = o3d.mv()
 579     grad, rgrad = o3d.grads()
 580  
 581  Then the gradient operator vector is ``grad`` (actually the user can give it any name he wants to). The derivatives of the multivector function ``F = o3d.mv('F', 'mv', f=True)`` are given by multiplying by the left geometric derivative operator and the right geometric derivative operator (:math:`\T{grad} = \nabla` and :math:`\T{rgrad} = \bar{\nabla}`). Another option is to use the radiant operator members of the geometric algebra directly where we have :math:`\nabla = {\texttt{o3d.grad}}` and
 582  :math:`\bar{\nabla} = {\texttt{o3d.rgrad}}`.
 583  
 584  .. math::
 585  
 586     \begin{aligned}
 587                 \nabla F &=  \texttt{grad*F} \\
 588                 F \bar{\nabla} &=  \texttt{F*rgrad} \\
 589                 \nabla {\wedge}F &=  \texttt{grad^F} \\
 590                 F {\wedge}\bar{\nabla} &=  \texttt{F^rgrad} \\
 591                 \nabla \cdot F &=  \texttt{grad|F} \\
 592                 F \cdot \bar{\nabla} &=  \texttt{F|rgrad} \\
 593                 \nabla \rfloor F &=  \texttt{grad<F} \\
 594                 F \rfloor \bar{\nabla} &=  \texttt{F<rgrad} \\
 595                 \nabla \lfloor F &=  \texttt{grad>F} \\
 596                 F \lfloor \bar{\nabla} &= \texttt{F>rgrad}
 597           \end{aligned}
 598  
 599  The preceding list gives examples of all possible multivector derivatives of the multivector function ``F`` where the operation returns a multivector function. The complementary operations
 600  
 601  .. math::
 602  
 603     \begin{aligned}
 604                 F \nabla &=  \texttt{F*grad} \\
 605                 \bar{\nabla} F &=  \texttt{rgrad*F} \\
 606                 F {\wedge}\nabla &=  \texttt{F^grad} \\
 607                 \bar{\nabla} {\wedge}F &=  \texttt{rgrad^F} \\
 608                 F \cdot \nabla &=  \texttt{F|grad} \\
 609                 \bar{\nabla}\cdot F &=  \texttt{rgrad|F} \\
 610                 F \rfloor \nabla &=  \texttt{F<grad} \\
 611                 \bar{\nabla} \rfloor F &=  \texttt{rgrad<F} \\
 612                 F \lfloor \nabla &=  \texttt{F>grad} \\
 613                 \bar{\nabla} \lfloor F &= \texttt{rgrad>F}
 614           \end{aligned}
 615  
 616  all return multivector linear differential operators.
 617  
 618  Submanifolds
 619  ------------
 620  
 621  In general the geometric algebra that the user defines exists on the tangent space of a manifold (see section :ref:`sect_manifold`). The submanifold class, ``Sm``, is derived from the ``Ga`` class and allows one to define a submanifold of a manifold by defining a coordinate mapping between the submanifold coordinates and the manifold coordinates. What is returned as the submanifold is the geometric algebra of the tangent space of the submanifold. The submanifold for a geometric algebra is
 622  instantiated with
 623  
 624  .. method:: galgebra.ga.Ga.sm(map, coords, root='e', norm=False)
 625     :noindex:
 626  
 627     To define the submanifold we must def a coordinate map from the coordinates of the submanifold to each of the coordinates of the base manifold. Thus the arguments ``map`` and ``coords`` are respectively lists of functions and symbols. The list of symbols, ``coords``, are the coordinates of the submanifold and are of length equal to the dimension of the submanifold. The list of functions, ``map``, define the mapping from the coordinate space of the submanifold to the coordinate space of the
 628     base manifold. The length of ``map`` is equal to the dimension of the base manifold and each function in ``map`` is a function of the coordinates of the submanifold. ``root`` is the root of the string that is used to name the basis vectors of the submanifold. The default value of ``root`` is ``e``. The result of this is that if the *sympy* symbols for the coordinates are ``u`` and ``v`` (two dimensional manifold) the text symbols for the basis vectors are ``e_u`` and ``e_v`` or in LaTeX
 629     :math:`e_{u}` and :math:`e_{v}`. As a concrete example consider the following code.
 630  
 631     .. literalinclude:: python/submanifold.py
 632  
 633     The output of this program (using LaTeX) is
 634  
 635     |image0|
 636  
 637     The base manifold, ``sp3d``, is a 3-d Euclidean space using standard spherical coordinates. The submanifold ``sph2d`` of ``sp3d`` is a spherical surface of radius :math:`1`. To take the sumanifold operation one step further the submanifold ``cir1d`` of ``sph2d`` is a circle in ``sph2d`` where the latitude of the circle is :math:`\pi/8`.
 638  
 639     In each case, for demonstration purposes, a scalar and vector function on each manifold is defined (``f`` and ``F`` for the 2-d manifold and ``h`` and ``H`` for the 1-d manifold) and the geometric derivative of each function is taken. The manifold mapping and the metric tensor for ``cir1d`` of ``sph2d`` are also shown. Note that if the submanifold basis vectors are not normalized\ [21]_ the program output is
 640  
 641     |image1|
 642  
 643  Linear Transformations
 644  ----------------------
 645  
 646  The mathematical background for linear transformations is in section :ref:`Ltrans`. Linear transformations on the tangent space of the manifold are instantiated with the ``Ga`` member function ``lt`` (the actual class being instantiated is ``Lt``) as shown in lines 12, 20, 26, and 44 of the code listing ``Ltrans.py``. In all of the examples in ``Ltrans.py`` the default instantiation is used which produces a general (all the coefficients of the linear transformation are symbolic constants) linear
 647  transformation. *Note that to instantiate linear transformations coordinates, :math:`{\left \{ {{\eb}_{i}} \rbrc}`, must be defined when the geometric algebra associated with the linear transformation is instantiated. This is due to the naming conventions of the general linear transformation (coordinate names are used) and for the calculation of the trace of the linear transformation which requires taking a divergence.* To instantiate a specific linear transformation the usage of ``lt()`` is
 648  
 649  .. method:: galgebra.ga.Ga.lt(M, f=False, mode='g')
 650     :noindex:
 651  
 652     ``M`` is an expression that can define the coefficients of the linear transformation in various ways defined as follows.
 653  
 654     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 655     | ``M``                      | Result                                                                                                                                                                                                                                                                                        |
 656     +============================+===============================================================================================================================================================================================================================================================================================+
 657     | string ``M``               | Coefficients are symbolic constants with names :math:`\T{M}^{x_{i}x_{j}}` where :math:`x_{i}` and :math:`x_{j}` are the names of the :math:`i^{th}` and :math:`j^{th}` coordinates (see output of ``Ltrans.py``).                                                                             |
 658     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 659     | char ``mode``              | If ``M`` is a string then ``mode`` determines whether the linear transformation is general, ``mode='g'``, symmetric, ``mode='s'``, or antisymmetric, ``mode='a'``. The default is ``mode='g'``.                                                                                               |
 660     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 661     | list ``M``                 | If ``M`` is a list of vectors equal in length to the dimension of the vector space then the linear transformation is :math:`\f{L}{\ebf_{i}} = \T{M}\mat{i}`. If ``M``\ is a list of lists of scalars where all lists are equal in length to the dimension of the vector space then the linear |
 662     |                            | transformation is\ :math:`\f{L}{\ebf_{i}} = \T{M}\mat{i}\mat{j}\ebf_{j}`.                                                                                                                                                                                                                     |
 663     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 664     | dict ``M``                 | If ``M`` is a dictionary the linear transformation is defined by :math:`\f{L}{\ebf_{i}} = \T{M}\mat{\ebf_{i}}`. If :math:`\ebf_{i}` is not in the dictionary then :math:`\f{L}{\ebf_{i}} =0`.                                                                                                 |
 665     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 666     | rotor ``M``                | If ``M`` is a rotor, :math:`\T{M}\T{M}^{\R}=1`, the linear transformation is defined by :math:`\f{L}{{\ebf}_{i}} = \T{M}{\ebf}_{i}\T{M}^{\R}` .                                                                                                                                               |
 667     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 668     | multivector function ``M`` | If ``M`` is a general multivector function, the function is tested for linearity, and if linear the coefficients of the linear transformation are calculated from :math:`\f{L}{\ebf_{i}} = \f{\T{M}}{\ebf_{i}}`.                                                                              |
 669     +----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 670  
 671     ``f`` is ``True`` or ``False``. If ``True`` the symbolic coefficients of the general linear transformation are instantiated as functions of the coordinates.
 672  
 673  The different methods of instantiation are demonstrated in the code ``LtransInst.py``
 674  
 675  .. literalinclude:: python/LtransInst.py
 676  
 677  with output
 678  
 679  |image2|
 680  
 681  The member function of the ``Lt`` class are
 682  
 683  .. automethod:: galgebra.lt.Lt.__call__(A)
 684     :noindex:
 685  
 686  .. automethod:: galgebra.lt.Lt.det
 687     :noindex:
 688  
 689  .. automethod:: galgebra.lt.Lt.adj
 690     :noindex:
 691  
 692  .. automethod:: galgebra.lt.Lt.tr
 693     :noindex:
 694  
 695  .. automethod:: galgebra.lt.Lt.matrix
 696     :noindex:
 697  
 698  The ``Ltrans.py`` demonstrate the use of the various ``Lt`` member functions and operators. The operators that can be used with linear transformations are ``+``, ``-``, and ``*``. If :math:`A` and :math:`B` are linear transformations, :math:`V` a multivector, and :math:`\alpha` a scalar then :math:`{{{\lp {A\pm B} \rp }}\lp {V} \rp } = {{A}\lp {V} \rp }\pm{{B}\lp {V} \rp }`, :math:`{{{\lp {AB} \rp }}\lp {V} \rp } = {{A}\lp {{{B}\lp {V} \rp }} \rp }`, and
 699  :math:`{{{\lp {\alpha A} \rp }}\lp {V} \rp } = \alpha{{A}\lp {V} \rp }`.
 700  
 701  The ``matrix()`` member function returns a *sympy* ``Matrix`` object which can be printed in IPython notebook. To directly print an linear transformation in *ipython notebook* one must implement (yet to be done) a printing method similar to ``mv.Fmt()``.
 702  
 703  Note that in ``Ltrans.py`` lines 30 and 49 are commented out since the latex output of those statements would run off the page. The use can uncomment those statements and run the code in the “LaTeX docs” directory to see the output.
 704  
 705  .. literalinclude:: python/Ltrans.py
 706  
 707  The output of this code is.
 708  
 709  |image3|
 710  
 711  Differential Operators
 712  ----------------------
 713  
 714  For the mathematical treatment of linear multivector differential operators see section :ref:`ldops`. The is a differential operator class ``Dop``. However, one never needs to use it directly. The operators are constructed from linear combinations of multivector products of the operators ``Ga.grad`` and ``Ga.rgrad`` as shown in the following code for both orthogonal rectangular and spherical 3-d coordinate systems.
 715  
 716  .. literalinclude:: python/Dop.py
 717  
 718  The output of this code is.
 719  
 720  |image4|
 721  
 722  Note that for print an operator in the IPython notebook one must implement (yet to be done) a printing method similar to ``mv.Fmt()``.
 723  
 724  Instantiating a Multi-linear Functions (Tensors)
 725  ------------------------------------------------
 726  
 727  The mathematical background for multi-linear functions is in section :ref:`MLtrans`. To instantiate a multi-linear function use
 728  
 729  .. class:: galgebra.lt.Mlt(f, Ga, nargs=None, fct=False)
 730     :noindex:
 731  
 732     Where the arguments are
 733  
 734     +-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 735     | ``f``     | Either a string for a general tensor (this option is included mainly for debugging of the ``Mlt`` class) or a multi-linear function of manifold tangent vectors (multi-vectors of grade one) to scalar. For example one could generate a custom |
 736     |           | python function such as shown in ``TensorDef.py`` .                                                                                                                                                                                             |
 737     +-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 738     | ``Ga``    | Geometric algebra that tensor is associated with.                                                                                                                                                                                               |
 739     +-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 740     | ``nargs`` | If ``f`` is a string then ``nargs`` is the number of vector arguments of the tensor. If ``f`` is anything other than a string ``nargs`` is not required since ``Mlt`` determines the number of vector arguments                                 |
 741     |           | from ``f``.                                                                                                                                                                                                                                     |
 742     +-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 743     | ``fct``   | If ``f`` is a string then ``fct=True`` forces the tensor to be a tensor field (function of the coordinates. If ``f`` anything other than a string ``fct`` is not required since ``Mlt`` determines whether the                                  |
 744     |           | tensor is a tensor field from ``f`` .                                                                                                                                                                                                           |
 745     +-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 746  
 747  .. literalinclude:: python/TensorDef.py
 748  
 749  Basic Multilinear Function Class Functions
 750  ------------------------------------------
 751  
 752  If we can instantiate multilinear functions we can use all the multilinear function class functions as described as follows. See section :ref:`MLtrans` for the mathematical description of each operation.
 753  
 754  .. automethod:: galgebra.lt.Mlt.__call__
 755     :noindex:
 756  
 757  .. automethod:: galgebra.lt.Mlt.contract
 758     :noindex:
 759  
 760  .. automethod:: galgebra.lt.Mlt.pdiff
 761     :noindex:
 762  
 763  .. automethod:: galgebra.lt.Mlt.cderiv
 764     :noindex:
 765  
 766  Standard Printing
 767  -----------------
 768  
 769  Printing of multivectors is handled by the module :mod:`printer` which contains a string printer class derived from the *sympy* string printer class and a latex printer class derived from the *sympy* latex printer class. Additionally, there is an :class:`printer.Eprint` class that enhances the console output of *sympy* to make the printed output multivectors, functions, and derivatives more readable. :class:`printer.Eprint` requires an ansi console such as is supplied in linux or the program *ConEmu* replaces ``cmd.exe``.
 770  
 771  For a windows user the simplest way to implement *ConEmu* is to use the *geany* editor and in the Edit\ :math:`\rightarrow`\ Preferences\ :math:`\rightarrow`\ Tools menu replace ``cmd.exe`` with\ [22]_
 772  
 773  ``"C:\Program Files\ConEmu\ConEmu64.exe" /WndW 180 /cmd %c``
 774  
 775  and then run an example *galgebra* program that used ``Eprint``. The default background and foreground colors make the output unreadable. To change these parameters to reasonable values:\ [23]_
 776  
 777  1. Right click on title bar of console.
 778  
 779  2. Open *setting* window.
 780  
 781  3. Open *colors* window.
 782  
 783  4. Set the following parameters to the indicated values:
 784  
 785     - Text: #0
 786     - Back: #7
 787     - Popup: #0
 788     - Back: #7
 789     - :math:`\rlap{ \checkmark }\square` Extend foreground colors with background #13
 790  
 791  If ``Eprint`` is called in a program (linux) when multivectors are printed the basis blades or bases are printed in bold text, functions are printed in red, and derivative operators in green.
 792  
 793  For formatting the multivector output there is the member function ``self.Fmt(fmt=1, title=None)`` which is documented in the multivector member functions. This member function works in the same way for LaTeX printing.
 794  
 795  If ``A`` is a multivector then ``str(A)`` returns a string in which the scalar coefficients of the multivector bases have been simplified (grouped, factored, etc.).
 796  
 797  Latex Printing
 798  --------------
 799  
 800  For latex printing one uses one functions from the ``ga`` module and one function from the ``printer`` module. The functions are
 801  
 802  .. autofunction:: galgebra.printer.Format
 803     :noindex:
 804  
 805  .. function:: galgebra.printer.Fmt(obj, fmt=1)
 806     :noindex:
 807  
 808     ``Fmt()`` can be used to set the global multivector printing format or to print a tuple, list, of dictionary\ [24]_. The modes and operation of ``Fmt()`` are as follows:
 809  
 810     +---------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
 811     | ``obj``             | Effect                                                                                                                                      |
 812     +=====================+=============================================================================================================================================+
 813     | ``obj=1,2,3``       | Global multivector format is set to 1, 2, or 3 depending on ``obj``. See multivector member function ``Fmt()`` for effect of ``obj`` value. |
 814     +---------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
 815     | obj=tuple/list/dict | The printing format of an object that is a tuple, list, or dict is controlled by the ``fmt`` argument in ``Fmt`` :                          |
 816     +---------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
 817     |                     | ``fmt=1``: Print complete ``obj`` on one line.                                                                                              |
 818     +---------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
 819     |                     | ``fmt=2``: Print one element of ``obj`` on each line.                                                                                       |
 820     +---------------------+---------------------------------------------------------------------------------------------------------------------------------------------+
 821  
 822  .. function:: galgebra.printer.xpdf(filename=None, debug=False, paper=(14, 11), crop=False)
 823     :noindex:
 824  
 825     This function from the ``printer`` module post-processes the output captured from print statements, writes the resulting latex strings to the file ``filename``, processes the file with pdflatex, and displays the resulting pdf file. All latex files except the pdf file are deleted. If ``debug = True`` the file ``filename`` is printed to standard output for debugging purposes and ``filename`` (the tex file) is saved. If ``filename`` is not entered the default filename is the root name of the
 826     python program being executed with ``.tex`` appended. The ``paper`` option defines the size of the paper sheet for latex. The format for the ``paper`` is
 827  
 828     ===================== =============================================================
 829     ``paper=(w,h)``       ``w`` is paper width in inches and
 830     \                     ``h`` is paper height in inches
 831     ``paper='letter'``    paper is standard letter size 8.5 in :math:`\times` 11 in
 832     ``paper='landscape'`` paper is standard letter size but 11 in :math:`\times` 8.5 in
 833     ===================== =============================================================
 834  
 835     The default of ``paper=(14,11)`` was chosen so that long multivector expressions would not be truncated on the display.
 836  
 837     If the ``crop`` input is ``True`` the linux ``pdfcrop`` program is used to crop the pdf output (if output is one page). This only works for linux installations (where ``pdfcrop`` is installed).
 838  
 839     The ``xpdf`` function requires that latex and a pdf viewer be installed on the computer.
 840  
 841     ``xpdf`` *is not required when printing latex in IPython notebook.*
 842  
 843  As an example of using the latex printing options when the following code is executed
 844  
 845  .. code:: python
 846  
 847     from printer import Format, xpdf
 848     from ga import Ga
 849     Format()
 850     g3d = Ga('e*x|y|z')
 851     A = g3d.mv('A', 'mv')
 852     print(r'\bm{A} =',A)
 853     print(A.Fmt(2,r'\bm{A}'))
 854     print(A.Fmt(3,r'\bm{A}'))
 855     xpdf()
 856  
 857  The following is displayed
 858  
 859  .. math::
 860  
 861     \begin{aligned}
 862           {\boldsymbol{A}} = & A+A^{x}{\boldsymbol{e_{x}}}+A^{y}{\boldsymbol{e_{y}}}+A^{z}{\boldsymbol{e_{z}}}+A^{xy}{\boldsymbol{e_{x}{\wedge}e_{y}}}+A^{xz}{\boldsymbol{e_{x}{\wedge}e_{z}}}+A^{yz}{\boldsymbol{e_{y}{\wedge}e_{z}}}+A^{xyz}{\boldsymbol{e_{x}{\wedge}e_{y}{\wedge}e_{z}}} \\
 863           {\boldsymbol{A}} =  & A \\  & +A^{x}{\boldsymbol{e_{x}}}+A^{y}{\boldsymbol{e_{y}}}+A^{z}{\boldsymbol{e_{z}}} \\  & +A^{xy}{\boldsymbol{e_{x}{\wedge}e_{y}}}+A^{xz}{\boldsymbol{e_{x}{\wedge}e_{z}}}+A^{yz}{\boldsymbol{e_{y}{\wedge}e_{z}}} \\  & +A^{xyz}{\boldsymbol{e_{x}{\wedge}e_{y}{\wedge}e_{z}}} \\
 864           {\boldsymbol{A}} =  & A \\  & +A^{x}{\boldsymbol{e_{x}}} \\  & +A^{y}{\boldsymbol{e_{y}}} \\  & +A^{z}{\boldsymbol{e_{z}}} \\  & +A^{xy}{\boldsymbol{e_{x}{\wedge}e_{y}}} \\  & +A^{xz}{\boldsymbol{e_{x}{\wedge}e_{z}}} \\  & +A^{yz}{\boldsymbol{e_{y}{\wedge}e_{z}}} \\  & +A^{xyz}{\boldsymbol{e_{x}{\wedge}e_{y}{\wedge}e_{z}}}\end{aligned}
 865  
 866  For the cases of derivatives the code is
 867  
 868  .. code:: python
 869  
 870     from printer import Format, xpdf
 871     from ga import Ga
 872  
 873     Format()
 874     X = x, y, z = symbols('x y z')
 875     o3d = Ga('e_x e_y e_z',g=[1,1,1],coords=X)
 876  
 877     f = o3d.mv('f', 'scalar', f=True)
 878     A = o3d.mv('A', 'vector', f=True)
 879     B = o3d.mv('B', 'grade2', f=True)
 880  
 881     print(r'\bm{A} =', A)
 882     print(r'\bm{B} =', B)
 883  
 884     print('grad*f =', o3d.grad*f)
 885     print(r'grad|\bm{A} =', o3d.grad|A)
 886     (o3d.grad*A).Fmt(2, r'grad*\bm{A}')
 887  
 888     print(r'-I*(grad^\bm{A}) =', -o3g.mv_I*(o3d.grad^A))
 889     print((o3d.grad*B).Fmt(2, r'grad*\bm{B}'))
 890     print(r'grad^\bm{B} =', o3d.grad^B)
 891     print(r'grad|\bm{B} =', o3d.grad|B)
 892  
 893     xpdf()
 894  
 895  and the latex displayed output is (:math:`f` is a scalar function)
 896  
 897  .. math:: \be {\boldsymbol{A}} = A^{x}{\boldsymbol{e_{x}}}+A^{y}{\boldsymbol{e_{y}}}+A^{z}{\boldsymbol{e_{z}}} \ee
 898  
 899  .. math:: \be {\boldsymbol{B}} = B^{xy}{\boldsymbol{e_{x}{\wedge}e_{y}}}+B^{xz}{\boldsymbol{e_{x}{\wedge}e_{z}}}+B^{yz}{\boldsymbol{e_{y}{\wedge}e_{z}}} \ee
 900  
 901  .. math:: \be {\boldsymbol{\nabla}}  f = \partial_{x} f{\boldsymbol{e_{x}}}+\partial_{y} f{\boldsymbol{e_{y}}}+\partial_{z} f{\boldsymbol{e_{z}}} \ee
 902  
 903  .. math:: \be {\boldsymbol{\nabla}} \cdot {\boldsymbol{A}} = \partial_{x} A^{x} + \partial_{y} A^{y} + \partial_{z} A^{z} \ee
 904  
 905  .. math::
 906  
 907     \begin{aligned}
 908      {\boldsymbol{\nabla}}  {\boldsymbol{A}} =  & \partial_{x} A^{x} + \partial_{y} A^{y} + \partial_{z} A^{z} \\  & +\lp - \partial_{y} A^{x} + \partial_{x} A^{y}\rp {\boldsymbol{e_{x}{\wedge}e_{y}}}+\lp - \partial_{z} A^{x} + \partial_{x} A^{z}\rp {\boldsymbol{e_{x}{\wedge}e_{z}}}+\lp - \partial_{z} A^{y} + \partial_{y} A^{z}\rp {\boldsymbol{e_{y}{\wedge}e_{z}}} \\ \end{aligned}
 909  
 910  .. math:: \be -I ({\boldsymbol{\nabla}} {\wedge}{\boldsymbol{A}}) = \lp - \partial_{z} A^{y} + \partial_{y} A^{z}\rp {\boldsymbol{e_{x}}}+\lp \partial_{z} A^{x} - \partial_{x} A^{z}\rp {\boldsymbol{e_{y}}}+\lp - \partial_{y} A^{x} + \partial_{x} A^{y}\rp {\boldsymbol{e_{z}}} \ee
 911  
 912  .. math::
 913  
 914     \begin{aligned}
 915      {\boldsymbol{\nabla}}  {\boldsymbol{B}} =  & \lp - \partial_{y} B^{xy} - \partial_{z} B^{xz}\rp {\boldsymbol{e_{x}}}+\lp \partial_{x} B^{xy} - \partial_{z} B^{yz}\rp {\boldsymbol{e_{y}}}+\lp \partial_{x} B^{xz} + \partial_{y} B^{yz}\rp {\boldsymbol{e_{z}}} \\  & +\lp \partial_{z} B^{xy} - \partial_{y} B^{xz} + \partial_{x} B^{yz}\rp {\boldsymbol{e_{x}{\wedge}e_{y}{\wedge}e_{z}}} \\ \end{aligned}
 916  
 917  .. math:: \be {\boldsymbol{\nabla}} {\wedge}{\boldsymbol{B}} = \lp \partial_{z} B^{xy} - \partial_{y} B^{xz} + \partial_{x} B^{yz}\rp {\boldsymbol{e_{x}{\wedge}e_{y}{\wedge}e_{z}}} \ee
 918  
 919  .. math:: \be {\boldsymbol{\nabla}} \cdot {\boldsymbol{B}} = \lp - \partial_{y} B^{xy} - \partial_{z} B^{xz}\rp {\boldsymbol{e_{x}}}+\lp \partial_{x} B^{xy} - \partial_{z} B^{yz}\rp {\boldsymbol{e_{y}}}+\lp \partial_{x} B^{xz} + \partial_{y} B^{yz}\rp {\boldsymbol{e_{z}}} \ee
 920  
 921  This example also demonstrates several other features of the latex printer. In the case that strings are input into the latex printer such as ``r'grad*\bm{A}'``, ``r'grad^\bm{A}'``, or ``r'grad*\bm{A}'``. The text symbols ``grad``, ``^``, ``|``, and ``*`` are mapped by the ``xpdf()`` post-processor as follows if the string contains an ``=``.
 922  
 923  ========== =================== ==============================
 924  original   replacement         displayed latex
 925  ``grad*A`` ``\bm{\nabla}A``    :math:`{\boldsymbol{\nabla}}A`
 926  ``A^B``    ``A\wedge B``       :math:`A\wedge B`
 927  ``A|B``    ``A\cdot B``        :math:`A\cdot B`
 928  ``A*B``    ``AB``              :math:`AB`
 929  ``A<B``    ``A\rfloor B``      :math:`A\rfloor B`
 930  ``A>B``    ``A\lfloor B``      :math:`A\lfloor B`
 931  ``A>>B``   ``A\times B``       :math:`A\times B`
 932  ``A<<B``   ``A\bar{\times} B`` :math:`A\bar{\times} B`
 933  ========== =================== ==============================
 934  
 935  If the first character in the string to be printed is a ``%`` none of the above substitutions are made before the latex processor is applied. In general for the latex printer strings are assumed to be in a math environment (equation or align) unless the first character in the string is a ``#``\ [25]_.
 936  
 937  To get the latex string representation of a multivector ``A``, the :func:`printer.latex` function can be used as ``latex(A)``.
 938  
 939  Printing Lists/Tuples of Multivectors/Differential Operators
 940  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 941  
 942  Since the expressions for multivectors or differential operators can be very long printing lists or tuples of such items can easily exceed the page with when printing in LaTeX or in “ipython notebook.” I order to alleviate this problem the function ``Fmt`` can be used.
 943  
 944  .. function:: galgebra.printer.Fmt(obj, fmt=0)
 945     :noindex:
 946  
 947     This function from the ``printer`` module allows the formatted printing of lists/tuples or multivectors/differential operators.
 948  
 949     +-----------+---------------------------------------------------------------------------------+
 950     | ``obj``   | ``obj`` is a list or tuple of multivectors and/or differential operators.       |
 951     +-----------+---------------------------------------------------------------------------------+
 952     | ``fmt=0`` | ``fmt=0`` prints each element of the list/tuple on an individual lines\ [26]_.  |
 953     +-----------+---------------------------------------------------------------------------------+
 954     |           | ``fmt=1`` prints all elements of the list/tuple on a single line\ [26]_.        |
 955     +-----------+---------------------------------------------------------------------------------+
 956  
 957     If l is a list or tuple to print in the LaTeX environment use the command
 958  
 959     .. code:: python
 960  
 961        print Fmt(l)  # One element of l per line
 962  
 963     or
 964  
 965     .. code:: python
 966  
 967        print Fmt(l, 1)  # All elements of l on one line
 968  
 969     If you are printing in “ipython notebook” then enter
 970  
 971     .. code:: python
 972  
 973        Fmt(l)  # One element of l per line
 974  
 975     or
 976  
 977     .. code:: python
 978  
 979        Fmt(l, 1)  # All elements of l on one line
 980  
 981  --------------
 982  
 983  
 984  .. [12]
 985     Since ``X`` or the metric tensor can be functions of coordinates the vector space that the geometric algebra is constructed from is not necessarily flat so that the geometric algebra is actually constructed on the tangent space of the manifold which is a vector space.
 986  
 987  .. [13]
 988     The signature of the vector space, :math:`(p,q)`, is required to determine whether the square of the normalized pseudoscalar, :math:`I`, is :math:`+1` or :math:`-1`. In the future the metric tensor would be required to create a generalized spinor (:cite:`Hestenes`, pg106).
 989  
 990  .. [14]
 991     Using LaTeX output if a basis vector is denoted by :math:`{{\eb}}_{x}` then :math:`{{\eb}}` is the root symbol and :math:`x` is the subscript
 992  
 993  .. [15]
 994     There is a multivector class, ``Mv``, but in order the insure that every multivector is associated with the correct geometric algebra we always use the member function ``Ga.mv`` to instantiate the multivector.
 995  
 996  .. [16]
 997     Denoted in text output by ``A__x``, etc. so that for text output ``A`` would be printed as ``A__x*e_x+A__y*e_y+A__z*e_z``.
 998  
 999  .. [18]
1000     In the future it should be possible to generate closed form expressions for :math:`e^{A}` if :math:`A^{r}` is a scalar for some integer :math:`r`.
1001  
1002  .. [21]
1003     Remember that normalization is currently supported only for orthogonal systems (diagonal metric tensors).
1004  
1005  .. [22]
1006     The 180 in the *ConEmu* command line is the width of the console you wish to display in characters. Change the number to suit you.
1007  
1008  .. [23]
1009     I am not exactly sure what the different parameter setting do. I achieved the result I wished for by trial and error. I encourage the users to experiment and share their results.
1010  
1011  .. [24]
1012     In *IPython notebook* tuples, or lists, or dictionaries of multivectors do print correctly. One mode of ``Fmt()`` corrects this deficiency.
1013  
1014  .. [25]
1015     Preprocessing do not occur for the IPython notebook and the string post processing commands ``%`` and ``#`` are not used in this case.
1016  
1017  .. [26]
1018     The formatting of each element is respected as applied by ``A.Fmt(fmt=1,2, or 3)`` where ``A`` is an element of ``obj`` so that if multivector/differential operation have been formatted to print on multiple lines it will printed on multiple lines.
1019  
1020  .. |image0| image:: images/submanifold.svg
1021  .. |image1| image:: images/submanifold1.svg
1022  .. |image2| image:: images/LtransInst.svg
1023  .. |image3| image:: images/Ltrans.svg
1024  .. |image4| image:: images/Dop.svg