%% ----------------------------CANTENSOR.DOC ---------------------------------
%
\documentstyle[reduce, art10]{article}    % Specifies the document style.
\setlength{\parindent}{.5cm}   % Fixes the indentation of the \par command.
\setlength{\parskip}{2mm}      % Fixes the skip of the \par command.
\renewcommand {\textwidth}{12cm}  %  Changes the width of the text.
\renewcommand {\textheight}{18cm}  % Changes the height of the text.
\baselineskip 11pt
%\headsep10mm
\newcommand{\nl}{\hfill\newline}  % Convenient to write arbitrary 
				  % stretched lines.
			   % May be put after the begin document. 
\newcommand{\none}{\nonumber \\}
%\makeindex
\title{{\tt CANTENS}\\
A Package for Manipulations \\
and Simplifications of Indexed Objects}
\date{}
\author{H. Caprasse and P. Fontaine\\
        Institut de Physique \\
        Sart-Tilman, B-4000 LIEGE\\
        email: {\tt  hubert.caprasse@ulg.ac.be}
}
\begin{document}
\maketitle
\section{Introduction}
Le logiciel {\tt CANTENSOR} est compos\'e de quatre  sous-logiciels
compl\'ementaires:
\begin{enumerate}
\item {\tt SPACE.RED} contient toutes les fonctionnalit\'es qui permettent
de d\'efinir le ou les espaces (sous-espaces) sans lesquels on d\'esire 
travauller. L'utilisateur est responsable
de la coh\'erence  de ses d\'efinitions (ult\'erieurement, des tests de 
compatibilit\'e seront introduits). 
\item {\tt GENTENS.RED} contient  le constructeur, les d\'efinitions  et 
les simplifications qui s'appliquent \`a tous les tenseurs g\'en\'eriques
ou \`a tous ceux que l'utilisateur peut introduire.
\item {\tt PART\_TNS.RED} contient les fonctions de simplification des 
tenseurs particuliers connus par le syst\`eme. 
\item {\tt CANON.RED} contient toutes les modifications au logiciel 
{\tt DUMMY.RED} ainsi que la fonction ma\^\i tresse de simplification 
des expressions tensorielles g\'en\'erales connect\'ees \`a l'action 
de la procedure de simplification de DUMMY \`a savoir de la 
fonction CANONICAL.
\end{enumerate}
\section{Description des fonctionnalit\'es}
\subsection{\tt SPACE.RED}  
Il contient le module {\em prepspace}. Au niveau de l'utilisateur, il
introduit 
\begin{itemize}
\item l'interrupteur ONESPACE qui est OFF par d\'efaut,
\item les fonctions DEFINE\_SPACES, SHOW\_SPACES et REM\_SPACES qui permettent 
d'introduire, de contr\^oler et de supprimer les propri\'et\'es des 
diff\'erents espaces introduits,
\item le mot cl\'e WHOLESPACE pour d\'esigner l'espace total,
\item les fonctions utilisateur  WHOLESPACE\_DIM, GLOBAL\_SIGN et SIGNATURE
qui permettent de conna\^\i tre, respectivement, la dimension de 
l'espace total, celle de la {\bf convention} de signe pour les composantes
temporelles de la longueur et le nombre de composantes du type temporel 
dans l'expression de cette longueur (ces caract\'eristiques n'ont pas de 
sens pour un espace g\'en\'eral mais sont importante pour tout espace 
pseudo-euclidien),
\item des fonctions pour exprimer l'appartenance des indices \`a 
un sous-espace,
\item des fonctions pour le contr\^ole des indices muets.
\end{itemize}
En voici la description d\'etaill\'ee.
Quand on entre dans le logiciel, les commandes suivantes peuvent
\^etre r\'ealis\'ees:
\begin{verbatim}

wholespace_dim ?; ==> dim 

global_sign ? ; ==> 1

signature ?; ==> 0
\end{verbatim}
'dim' est la dimension de l'espace global, 1 correspond \`a la convention 
des physiciens des hautes \'energies pour le m\'etrique de l'espace de 
Minkowski. La signature 0  indique que l'espace est euclidien.
Au d\'epart, c'est l'unique espace qui est d\'efini. Le logiciel 
permet d'introduire plusieurs espaces, mais, par d\'efaut, il suppose 
qu'il n'y a qu'un seul espace. La possibilit\'e de travailler dans un 
ou plusieurs espaces est r\'egie par l'interrupteur ONESPACE qui est 
ON au d\'epart:
\begin{verbatim}
   onespace ?; ==> yes

   off onespace;

   onespace ?; ==> no
\end{verbatim}
Il ne faut pas travailler en OFF ONESPACE si ce n'est pas 
n\'ecessaire. 
\subsubsection{La modification de l'espace par d\'efaut}
Bien entendu, on peut modifier les caract\'eristiques de l'espace par 
d\'efaut. Pour cela, on utilise les fonctions ci-dessus. Par exemple,
si l'on veut que l'espace global soit celui de Minkowski, et que la 
convention pour la m\'etrique soit celle des astrophysiciens, on entre:

\begin{verbatim}
   wholespace_dim 4; ==> 4

   signature 1; ==> 1

   global_sign(-1); ==> -1
\end{verbatim}
En principe, le nombre de coordonn\'ees du type temporel peut \^etre 
un nombre entier arbitraire. Cependant, jusqu'ici, les fonctions 
de simplification ne sont d\'efinies que si elle est 0 ou 1.
Toutes les d\'efinitions ci-dessus sont, naturellement, disponibles quand
ONESPACE est ON. Ce sont les pr\'ecisions essentielles qu'il faut pouvoir 
introduire et qui permettent au logiciel de travailler le plus efficacement.
La fonction SHOW\_SPACES, qui est utile lorsque ONESPACE est OFF, donne 
toujours la liste nulle:
\begin{verbatim}
   show_spaces(); ==> {}
\end{verbatim}
ce qui indique que l'on travaille toujours avec l'espace par d\'efaut.
Il est important de remarquer que cet espace {\em n'a pas de nom}.
\subsubsection{La construction des espaces quand ONESPACE est OFF}
Il faut maintenant d\'efinir les espaces et sous-espaces avec plus de 
pr\'ecision.
La fonction DEFINE\_SPACES devient active. Elle agit comme suit
\begin{verbatim}
   define_spaces s={ds,euclidian} 
 
             ou
          
   define_spaces s={ds,signature=<number>,indexrange=a .. b}
\end{verbatim}
{\bf s} est le nom de l'espace, {\bf ds} est sa dimension, puis 
il est d\'eclar\'e euclidien ou sa signature est d\'efinie. Enfin, il est 
possible de d\'eclarer la port\'ee des indices num\'eriques. Par exemple,
 {\bf 0 .. 3} si c'est l'espace de Minkowski.
Si {\bf s } est le nom {\bf wholespace}, la d\'eclaration d'un 
``indexrange'' est {\em inutile} comme l'exemple suivant le 
montre~:
\begin{verbatim}
   define_spaces wholespace={6,signature=1,indexrange=0 .. 5}; ==>t

   show_spaces(); ==> {{wholespace,6,signature=1}}  
\end{verbatim}
Dans l'exemple suivant,en supposant au d\'epart qu'aucun espace 
n'est d\'efini, on introduit, comme espace global, un espace 
\`a 11 dimension de signature \'egale \`a 1. Comme dit plus haut, il ne 
faut pas d\'eclarer 
que les indices num\'eriques vont de 0 \`a 10.~:
\begin{verbatim}
  define_spaces wholespace={11,signature=1}; ==> t

  define_spaces mink={4,signature=1,indexrange=0 .. 3}; ==> t
  
  define_spaces eucl={6,euclidian,indexrange=4 .. 9}; ==> t      

  show_spaces(); ==> 

                      {{wholespace,11,signature=1}

                       {mink,4,signature=1,indexrange=0..3},

                      {eucl,6,euclidian,indexrange=4..9}}
  
\end{verbatim}
La fonction SHOW\_SPACES permet de v\'erifier la consistance des 
donn\'ees. Si on s'est tromp\'e ou si on veut modifier les d\'efinitions
introduites, on ne peut directement red\'efinir les espaces par 
DEFINE\_SPACES (pour des raisons de s\'ecurit\'e). Ainsi,
\begin{verbatim}
   define_spaces eucl={7,euclidian,indexrange=4 .. 9}; ==> 
     *** Warning: eucl
          cannot be (or is already) defined as space identifier
         
         t

   show_spaces(); ==>

                      {{wholespace,11,signature=1}

                       {mink,4,signature=1,indexrange=0..3},

                      {eucl,6,euclidian,indexrange=4..9}}

\end{verbatim}
Ce qui montre que l'espace n'a pas \'et\'e red\'efini.
Pour le red\'efinir, il faut d'abord utiliser REM\_SPACES qui admet un 
nombre arbitraire d'arguments qui sont les identificateurs des espaces.
Supposons que nous voulions changer eucl en un espace \`a 5 dimensions,
voici comment on proc\`ede:
\begin{verbatim}
   rem_spaces eucl; ==> t

   show_spaces(); ==>

                {{wholespace,11,signature=1},

                  {mink,4,signature=1,indexrange=0..3}}

   define_spaces eucl={7,euclidian,indexrange=4 .. 10}; ==> t

   show_spaces(); ==> 

                  {{wholespace,11,signature=1},

                    {mink,4,signature=1,indexrange=0..3},

                    {eucl,7,euclidian,indexrange=4..10}}
\end{verbatim}
L'utilisateur est responsable de la coh\'erence de ses entr\'ees. 
Si, par exemple, on ajoute un sous-espace, le syst\`eme ne dit rien bien 
qu'une dimension soit de trop:
\begin{verbatim}
   define_spaces eucl1={1,euclidian,indexrange=11 .. 11}; ==> t

   show_spaces(); ==>

          {{wholespace,11,signature=1},

           {mink,4,signature=1,indexrange=0..3},

           {eucl,7,euclidian,indexrange=4..10},

           {eucl1,1,euclidian,indexrange=11..11}}
\end{verbatim}
Quand les indices sont symboliques, les routines de simplification 
des tenseurs ne peuvent tenir compte de leur appartenance \`a tel ou 
\`a tel sous-espace que si cette appartenance est d\'eclar\'ee. Donc,
par d\'efaut, tout indice symbolique est suppos\'e appartenir \`a l'espace
global ({\tt wholespace}). Pour qu'il n'en soit pas ainsi, on peut d\'eclarer
l'appartenance d'un ou plusieurs indices \`a un sous-espace d\'etermin\'e
en utilisant la fonction MK\_IDS\_BELONG\_SPACE. La syntaxe est
\begin{verbatim}
   mk_ids_belong_space(<list of indices>,<sub-space identifier>)
\end{verbatim}
Par exemple :
\begin{verbatim}
   mk_ids_belong_space({a0,a1,a2,a3},mink); ==> t

   mk_ids_belong_space({x,y,z,u,v},eucl); ==> t 
\end{verbatim}
On peut alors d\'efinir un tenseur qui a une structure ``bloc-diagonale''.  
La fonction MK\_IDS\_BELONG\_WHOLESPACE permet de les replacer dans l'espace 
global. Par exemple, si l'on fait:
\begin{verbatim}
 mk_ids_belong_anyspace a1,a2; ==> t
\end{verbatim}
les indices a1 et a2 appartiennent \`a  l'espace ``wholespace''.

Un statut sp\'ecial est r\'eserv\'e \`a la manipulation des indices 
MUETS (de sommation) :
 En effet, lorsque le logiciel voit qu'un m\^eme indice 
appara\^\i t dans la liste des indices covariants et contravariants, 
cet indice est automatiquement consid\'er\'e comme muet et plac\'e 
dans une liste sp\'eciale.
Le logiciel fait en sorte que cet indice ne soit plus manipulable comme
un indice libre  et g\'en\`ere, si n\'ecessaire, un message d'erreur.
De plus, il fait savoir  au logiciel {\tt DUMMY} que cet indice doit 
\^etre consid\'er\'e comme muet. Il en r\'esulte, qu'apr\`es un 
certain temps d'utilisation, beaucoup d'indices peuvent avoir \'et\'e
d\'eclar\'es muets \`a l'insu de l'utilisateur. Ce dernier doit donc 
pouvoir voir \`a chaque instant quels sont les indices muets et il doit 
pouvoir les \'eliminer, si n\'ecessaire. Pour cela, il dispose de deux 
fonctions : DUMMY\_INDICES, REM\_DUMMY\_INDICES et REM\_DUMMY\_IDS. La 
premi\`ere montre la liste compl\`ete des indices muets, la seconde 
permet de les \'eliminer tous et la troisi\`eme permet de les \'eliminer
s\'electivement. Comme, pour l'instant, nous n'avons pas encore introduit
d'expression tensorielle, il n'en n'existe pas:
\begin{verbatim}
   dummy_indices(); ==> {}  
\end{verbatim}
\subsection{{\tt GENTENS.RED}}
\subsubsection{Les tenseurs g\'en\'eriques}
Les tenseurs g\'en\'eriques manipul\'es par le logiciel sont des objects
beaucoup plus g\'en\'eraux que les tenseurs au sens habituel du terme
dans la mesure o\`u il ne sont pas contraints par l'existence d'une loi
de transformation sous les changements de coordonn\'ees. Pour le 
logiciel, un tenseur est une grandeur indic\'ee qui distingue deux types 
d'indices que, pour des raisons \'evidentes, nous appelons {\tt covariants}
et {\tt contravariants}. C'est aussi une grandeur qui suppose applicables
les r\`egles de sommation des indices muets du calcul tensoriel usuel.
Enfin, c'est une grandeur dont les propri\'et\'es sont ou peuvent \^etre 
rendues sensibles aux propri\'et\'es d'un espace. Enfin, c'est une grandeur 
qui peut \^etre rendue dependante, implicitement ou explicitement d'un
nombre arbitraire de variables. Ainsi, les tenseurs d\'efinis par 
le logiciel peuvent repr\'esenter aussi des spineurs, des \'el\'ements 
d'une alg\`ebre (car il peuvent \^etre d\'eclar\'es non-commutatifs ou 
anticommutatifs) et des op\'erateurs de champs.  
L'utlisateur peut introduire autant de tenseurs qu'il d\'esire. Les 
tenseurs qu'il cr\'ee par la commande TENSOR ont un nombre d'indices 
covariants et contravariants qui est arbitraire. Les composantes n'ont 
pas de valeur et les indices appartiennent par d\'efaut \`a l'espace global.
Ces indices peuvent \^etre num\'eriques ou symboliques. Quand on d\'eclare 
explicitement la d\'ependance, il faut, en principe, (nous d\'ecrirons 
des cas o\`u ce n'est pas n\'ecessaire plus loin.)  
placer les variables dans une liste. La position de la 
liste  par rapport aux indices est laiss\'ee au choix de l'utilisateur.
\begin{verbatim}
   tensor te; ==> t

   te(3,a,-4,b,-c,7); ==> 

            3 a   b   7
          te
                4   c

  te(3,a,{x,y},-4,b,-c,7); ==>


             3 a   b   7
          te            (x,y)
                 4   c


   te(3,a,-4,b,{u,v},-c,7); ==>

             3 a   b   7
          te            (u,v)
                 4   c

   te({x,y}); ==>  te(x,y)

\end{verbatim}
On peut se passer de placer les variables dans une liste si on les d\'eclare 
comme variables. Dans ce cas, il faut prendre garde de ne pas substituer une
variable ainsi d\'eclar\'ee par un nombre car ce nombre serait compris comme
un indice par le logiciel~:
\begin{verbatim}

   make_variables x,y; ==> t

   te(x,y); ==> te(x,y)


   te(x,y,a); ==> 

             a
          te  (x,y)

   remove_variables x; ==> t

   te(x,y,a); ==>

             x a
          te    (y)

\end{verbatim}
Avec la d\'eclaration MAKE\_VARIABLES, le tenseur scalaire 
peut \^etre manipul\'e comme un op\'erateur usuel. Encore une fois si l'on 
s'attend \`a devoir r\'ealiser des substitutions num\'eriques d'une 
ou plusieurs variables, il faut {\em toujours} les placer dans une liste.
La d\'ependance peut aussi \^etre d\'eclar\'ee implicitement par la 
commande de {\tt REDUCE} DEPEND. Cette commande est \'etendue pour que la 
d\'eclaration de d\'ependance d'un tenseur par rapport \`a un second tenseur 
soit valable pour toutes les composantes de ce dernier.
\begin{verbatim}
   depend op1,op2(x);

   df(op1,op2(x)); ==> df(op1,op2(x))

   df(op1,op2(y)); ==> 0

   tensor te,x;

   depend te,op1(x);

   df(te(a,-b),op1(x)); ==> 

               a
          df(te   ,op1(x))
                 b

   df(te(a,-b),op1(y)); ==> 0

   depend te,x;

   df(te(a,-b),x(c)); ==>

               a    c
          df(te   ,x )
                 b
\end{verbatim}
Ainsi quand les deux objets sont des tenseurs, dans la d\'eclaration de
d\'ependance, on peut oublier les {\em indices}. 
% PROBLEME:
%56: depend te,y({u});
%
%57: lisp depl!*;
%
%((te_ (y (list u))) (te (y (list u))))
%
%58: df(te(a,-b),y({c}));
%
%     a
%df(te   ,y(c))
%       b
%
% Comme c est une variable, ici, on aimerait 0. Alors ce serait compatible 
%avec la derivee VARIATIONNELLE. 
Notons que les indices peuvent \^etre aussi bien num\'eriques que symboliques.
La commande SUB du syst\`eme, {\em \`a une exception pr\`es}, permet la 
substitution~:
\begin{verbatim}
   sub(a=-c,te(a,b)); ==>

              b
          te
            c

   sub(a=-1,te(a,b)); ==>

              b
          te
            1

   sub(a=-0,te(a,b)); ==> 

            0 b
          te  

   sub(a=-!0,te(a,b)); ==>

              b
          te
            0
\end{verbatim}
La substitution de a par -0 ne s'est pas faite correctement car la 
fonction SUB a directement remplac\'e -0 par +0. Le dernier exemple 
montre comment il faut proc\'eder pour \'eviter le probl\`eme. 

Le syst\`eme reconna\^\i t automatiquement les indices muets qui 
sont apparents dans la composante tensorielle entr\'ee par l'utilisateur.
Au d\'epart, il n'existe pas d'indices muets comme la fonction 
DUMMY\_INDICES permet de le constater. 
\begin{verbatim}
   dummy_indices(); ==> {}

   te(a,b,-c,-a); ==>

            a b
          te
                c a

   dummy_indices(); ==> {a}

   te(a,b,-c,a); ==> ***** ((c) (a b a)) are inconsistent lists of indices

   sub(c=b,te(a,b,-c,-a)); ==>

            a b
         te
                b a

   dummy_indices(); ==> {b,a}

   te(d,-d,d); ==> ***** ((d) (d d)) are inconsistent lists of indices

   dummy_indices(); ==> {d,b,a}

   rem_dummy_ids d; ==> t

   dummy_indices(); ==> {b,a}

   rem_dummy_indices(); ==> t

   dummy_indices(); ==> {}
\end{verbatim}
Dans le cas d'un seul espace de dimension symbolique, c'est la seule 
v\'erification de la coh\'erence au niveau des indices qui peut \^etre 
faite. Si la dimension 
de l'espace global est un entier, le logiciel v\'erifie que les indices 
num\'eriques n'ont pas une valeur plus grande que la dimension de l'espace.
Quand on travaille dans un seul espace, deux cas se pr\'esentent. Soit la 
signature est \'egale \`a z\'ero et alors le syst\`eme consid\`ere que les 
indices num\'eriques vont de 1 \`a 4. Soit la signature est \'egale \`a 1 
et alors le syst\`eme consid\`ere que les indices vont de 0 \`a 3. Le cas 
d'une signature plus grande que 1 n'est pas pr\'evu.
\begin{verbatim}
   wholespace_dim 4; ==> 4

   signature 0; ==> 0

   te(3,a,-b,7); ==> ***** numeric indices out of range

   te(3,a,-b,3); ==>

            3 a   3
          te
                b

   te(3,a,-4,b,-c,7); ==> ***** numeric indices out of range


   te(4,a,-b,4); ==>

            4 a   4
          te
                b

   sub(a=5,te(3,a,-b,3)); ==> ***** numeric indices out of range

   signature 1; ==> 1

   te(4,a,-b,4); ==> ***** numeric indices out of range

   te(0,a,-b,3); ==>

             0 a   3
           te
                 b
\end{verbatim}
Si on travaille dans plusieurs espaces, on peut d\'eclarer que le tenseur 
appartient \`a l'un d'eux. Il en va de m\^eme pour les indices symboliques
et num\'eriques. L'appartenance  de ces derniers \`a l'un ou l'autre des 
sous-espaces est contr\^ol\'ee par la d\'eclaration 
\begin{verbatim}

indexrange = a .. b

\end{verbatim}
dans la commande \index{DEFINE\_SPACES}DEFINE\_SPACES.
\begin{verbatim}
   define_spaces wholespace={6,signature=1); ==> t

   show_spaces(); ==> {{wholespace,6,signature=1}}

   make_tensor_belong_space(te,wholespace); ==> wholespace

   te(4,a,-b,6); ==> ***** numeric indices out of range

   te(4,a,-b,5); ==>

            4 a   5
          te
                b

   rem_spaces wholespace;

   define_spaces wholespace={4,euclidean}; ==> t

   te(a,5,-b); ==> ***** numeric indices out of range

   te(a,4,-b); ==>

            a 4
          te
                b

   define_spaces eucl={1,signature=0}; ==> t

   show_spaces(); ==>

          {{wholespace,5,signature=1},

           {eucl,1,signature=0}}

   make_tensor_belong_space(te,eucl); ==> eucl

   te(1); ==>

            1
          te

   te(2); ==> ***** numeric indices out of range

   te(0); ==>

            0
          te
\end{verbatim}
Il est important de noter que la commande 
{\tt make\_tensor\_belong\_space} n'est {\em active} que pour les 
symboles {\em qui ont \'et\'e pr\'ealablement d\'efinis comme tenseurs par 
la commande {\tt tensor}}.   

Pour que l'indice 0  ne soit pas repris dans les indices d'un espace 
euclidien, nous  devons sp\'ecifier l'indexrange de l'espace {\tt eucl}.
\begin{verbatim}
   rem_spaces eucl; ==> t

   define_spaces eucl={1,signature=0,indexrange=1 .. 1}; ==> t

   te(0); ==> ***** numeric indices do not belong to subspace

   te(1); ==>

            1
          te

   te(2); ==> ***** numeric indices do not belong to subspace
\end{verbatim}
Il appartient \`a l'utilisateur de construire lui-m\^eme les propri\'et\'es
particuli\`eres du tenseur.
Les propri\'et\'es de sym\'etrie sur les indices sont ais\'ees \`a d\'efinir.
L'utilisateur a la possibilit\'e de d\'eclarer un tenseur g\'en\'erique 
sym\'etrique ou antisym\'etrique par les commandes SYMMETRIC et 
ANTISYMMETRIC de {\tt REDUCE}. Quand nous discuterons de l'extension 
du logiciel DUMMY, nous consid\'ererons les sym\'etries partielles.
\begin{verbatim}
   symmetric te; 

   te(b,a,d,c,-a); ==>

               a b c d
           te
             a

   te({x,y,z},a,b,c); ==>

             a b c
          te      (x,y,z)



   te({x,y,z},b,a,c); ==>

             a b c
          te      (x,y,z)


   te({y,x,z},b,a,c); ==>

             a b c
          te      (y,x,z)

   remsym te;

   te(b,a,d,c,-a); ==>

            b a d c
          te
                    a


   antisymmetric te;

   te(b,a1,d,c,b); ==> 0

   te(b,a1,c,d,b1); ==> 

               a1 b b1 c d
           - te

   remsym te;
\end{verbatim}
On peut aussi d\'eclarer un tenseur g\'en\'erique  du type bloc-diagonal
en utilisant la fonction MAKE\_BLOC\_DIAGONAL.
Dans ce cas, si l'on d\'esire une simplification sur les indices symboliques,
il faut d\'eclarer l'appartenance de ceux-ci aux sous-espaces qui ont \'et\'e 
definis \`a l'aide de la fonction MK\_IDS\_BELONG\_SPACE. 
Avec les sous-espaces de l'exemple pr\'ec\'edent, l'exemple suivant
illustre ce que l'on peut faire~:
\begin{verbatim}
   define_spaces wholespace={6,signature=1}; ==> t

   define_spaces mink={4,signature=1,indexrange=0 .. 3}; ==> t

   define_spaces eucl={3,euclidian,indexrange=4 .. 6}; ==> t

   show_spaces(); ==>

          {{wholespace,6,signature=1},

           {mink,4,signature=1,indexrange=0..3},

           {eucl,3,euclidian,indexrange=4..6}}

   make_tensor_belong_space(te,eucl); ==> eucl

   make_bloc_diagonal te; ==> t

   mk_ids_belong_space({a,b,c},eucl); ==> t

   te(a,b,z); ==>

            a b z
          te

   mk_ids_belong_space({m1,m2},mink); ==> t

   te(a,b,m1); ==> 0

   te(a,b,m2); ==> 0

   mk_ids_belong_anyspace a,b,c,m1,m2; ==> t

   te(a,b,m2); ==>

            a b m2
          te

\end{verbatim}
La derni\`ere commande permet de replacer les indices dans 
l'espace total. Le tenseur, bien que bloc-diagonal, ne s'annulle plus
puisque le syst\`eme ne sait plus que a,b et m2 ne se trouvent pas 
dans le m\^eme sous-espace.

Pour particulariser le tenseur, l'utilisateur dispose de deux moyens:
\begin{enumerate}
\item L'assignation {\em globale} \`a l'aide de l'op\'erateur {\bf ==}.
\item L'assignation {\em locale} \`a l'aide des r\`egles.
\end{enumerate}
L'assignation globale implique une \'evaluation du membre de gauche car 
il faut qu'avant l'assignation le syst\`eme reconnaisse les indices et 
transforme ad\'equatement les indices num\'eriques~:
Pour la clart\'e, les tests ci-dessous sont r\'ealis\'es dans un
unique espace (SHOW\_SPACES() donne {\tt \{\}}.)
\begin{verbatim}
   te({x,y},a,-0)==x*y*te(a,-0); ==>

            a
          te   *x*y
              0

 te({x,y},a,-0); ==>

            a
          te   *x*y
              0

   te({x,y},a,0); ==>

  
             a 0
          te    (x,y)
\end{verbatim}
L'assignation d'un \'el\'ement ne peut se faire plusieurs fois de 
suite sans l'effacer au pr\'ealable.
\begin{verbatim}
   te({x,y},a,-0)==x*y*te(a,-0); ==>

                  a
          ***** te   *x*y invalid as setvalue kernel
                    0

   rem_value_tens te({x,y},a,-0);

   te({x,y},a,-0); ==>

             a
          te    (x,y)
               0

   te({x,y},a,-0)==(x+y)*te(a,-0);

            a
          te   *(x + y)
              0
\end{verbatim}
Dans l'application ci-dessous, l'utilisation de la notation tensorielle 
rend le calcul plus lisible et \'evite d'introduire {\bf deux} op\'erateurs.
L'effacement de l'ensemble des valeurs se fait aussi \`a l'aide de 
la fonction REM\_VALUE\_TENS~:  
\begin{verbatim}
   te(1)==sin th * cos phi; ==> cos(phi)*sin(th)

   te(-1)==sin th * cos phi; ==> cos(phi)*sin(th)

   te(2)==sin th * sin phi; ==> sin(phi)*sin(th)

   te(-2)==sin th * sin phi; ==> sin(phi)*sin(th)

   te(3)==cos th ; ==> cos(th)

   te(-3)==cos th ; ==> cos(th)

   for i:=1:3 sum te(i)*te(-i); ==>

                  2        2          2           2        2
          cos(phi) *sin(th)  + cos(th)  + sin(phi) *sin(th)

   rem_value_tens te; 

   te(2); ==> 

            2
         te 
\end{verbatim}
Les autres m\'ethodes de particularisation sont les r\`egles \`a savoir 
le LET, le FOR ALL LET et le WHERE de {\tt REDUCE}..	
\begin{verbatim}
   let te({x,y},-0)=x*y;

   te({x,y},-0); ==> x*y

   te({x,y},+0); ==> 

             0
          te  (x,y)


   te({x,u},-0); ==>

          te  (x,u)
             0


   for all x,a let te({x},a,-b)=x*te(a,-b);

   te({u},1,-b); ==>

            1
          te   *u
              b

   te({u},c,-b); ==>

            c
          te   *u
              b

   te({u},b,-b); ==>

            b
          te   *u
              b

   te({u},a,-a); ==>

             a
          te    (u)
               a

   for all x,a clear te({x},a,-b);

   te({u},c,-b); ==>

             c
          te    (u)
               b

   for all a,b let te({x},a,-b)=x*te(a,-b);

   te({x},c,-b); ==>

            c
          te   *x
              b

   te({x},a,-a); ==>

            a
          te   *x
              a

\end{verbatim}
Un probl\`eme subsiste avec -0~:
\begin{verbatim}
   te({x},a,-0); ==>

             a
          te    (x)
               0

   te({x},0,-!0); ==>

            0
          te   *x
              0
\end{verbatim}
L'exemple suivant d'application des r\`egles locales met aussi en \'evidence 
que, pour le logiciel, les tenseurs ne sont pas des grandeurs qui se transforment 
d'une mani\`ere sp\'ecifique dans un changement de coordonn\'ees.
\begin{verbatim}
   rul:={te(~a) => sin a}; ==>

                     a
          rul := {te  => sin(a)}
                    


   te(1) where rul; ==> sin(1)

   te(1); ==>

              1
            te
\end{verbatim}
Une seconde difficult\'e \'emerge ici~: quand les r\`egles s'appliquent
sur un tenseur qui d\'epend explicitement des variables, la position initiale
des variables par rapport aux indices a de l'importance pour que la r\`egle
s'applique {\em automatiquement}. {\bf La liste contenant les 
variables doit \^etre plac\'ee la PREMIERE cad. AVANT tous les indices}.
Si ce n'est pas le cas, il faut appliquer REVAL OU SIMPLIFY sur l'expression.
Voici une illustration~:
\begin{verbatim}
   rul1:={te(~a,{~x,~y}) => x*y*sin(a)}; ==>

    
                     ~a
          rul1 := {te   (~x,~y) => x*y*sin(a)}


   te(a,{x,y}) where rul1; ==>

             a
          te  (x,y)


   reval(te(a,{x,y})) where rul1; ==>  sin(a)*x*y

   te({x,y},a) where rul1; ==> sin(a)*x*y

 
   rul2:={te(-~a,{~x,~y}) => x*y*sin(-a)};


          rul2 := {te   (~x,~y) => x*y*sin(-a)}
                     ~a

   te(-a,{x,y}) where rul2; ==>

          te  (x,y)
            a

   te({x,y},-a) where rul2; ==> -sin(a)*x*y

   reval te(-a,{x,y}) where rul2; ==> -sin(a)*x*y
\end{verbatim}
Ceci est d\^u au fait que la fonction de simplification place la 
liste des variables devant tous les indices et au fait que la fonction 
d'impression ne garde pas de trace de cet ordre afin d'augmenter la 
lisibilit\'e du r\'esultat. Il n'est pas possible de rem\'edier \`a ce 
probl\`eme sans engendrer des inconv\'enients encore plus 
importants. Il est important de noter que, d\`es qu'il y eu une premi\`ere 
\'evaluation il n'y a plus de probl\`eme. Donc l'impact de ce d\'efaut 
sur un calcul effectif est quasi inexistant puisque dans ce cas les 
expressions qui sont entr\'ees sont r\'e\'evalu\'ees d\`es le d\'epart 
du calcul. 

L'utilisateur dispose de la fonction REM\_TENSOR pour \'eliminer un 
tenseur qui a \'et\'e d\'efini. Cette fonction poss\`ede la syntaxe
\begin{verbatim}
   rem_tensor t1,t2,t3 ....;
\end{verbatim}
Le syst\`eme v\'erifie, toutes les fois que c'est possible, la coh\'erence 
des objets entr\'es par l'utilisateur. Dans le cas o\`u l'on travaille
dans un seul espace (ONESPACE est ON), seuls, la compatibilit\'e 
des indices num\'eriques avec la dimension de l'espace peut \^etre 
v\'erifi\'e. Cette v\'erification n'est possible que si la dimension est
enti\`ere. Par d\'efaut, l'espace est euclidien. On a~: 
\begin{verbatim}
 
   wholespace_dim 4; ==> 4

   wholespace_dim ?; ==> 4

   signature ?; ==> 0

   te({y,x,z},b,a,4); ==>

             4 a b
          te      (y,x,z)

   te({y,x,z},b,a,5); ==>

          ***** numeric indices out of range

   signature 1;

   signature ?; ==> 1

   te({y,x,z},b,a,4); ==>

           ***** numeric indices out of range

   te({y,x,z},b,-0,3); ==>

               3 b
          te      (y,x,z)
             0
\end{verbatim}
Dans le cas o\`u la signature est 1, les indices sont suppos\'es \^etre
0,1,2,3 comme c'est usuellement le cas. Il est important de noter que,
d\`es que l'espace global a \'et\'e d\'efini explicitement, il n'est 
plus possible (m\^eme quand ONESPACE est ON) de redimensioner l'espace 
par la fonction WHOLESPACE\_DIM  pour des raisons \'evidentes de 
consistence. Si l'on veut que cette fonction soit r\'eactiv\'ee, il est
n\'ecessaire d'utiliser REM\_SPACES pour \'eliminer l'espace global.

Lorsque l'on travaille dans plusieurs espaces (ONESPACE est OFF),
on peut d\'eclarer qu'un 
tenseur g\'en\'erique appartient \`a un sous-espace gr\^ace \`a la 
fonction \index{MAKE\_TENSOR\_BELONG\_SPACE}MAKE\_TENSOR\_BELONG\_SPACE~:
\begin{verbatim}
   off onespace;

   define_spaces wholespace={6,signature=1}; ==> t

   define_spaces mink={4,signature=1,indexrange=0 .. 3} ==> t

   define_spaces eucl={3,euclidian,indexrange=4 .. 6}; ==> t

   show_spaces(); ==>

          {{wholespace,6,signature=1},

           {mink,4,signature=1,indexrange=0..3},

           {eucl,3,euclidian,indexrange=4..6}}

   make_tensor_belong_space(te,eucl); ==> eucl

   te({y,x,z},b,-0,3); ==>

          ***** numeric indices do not belong to subspace

   te({y,x,z},b,3,3); ==>

          ***** numeric indices do not belong to subspace


   te({y,x,z},b,4,6); ==>

             4 6 b
          te      (y,x,z)
\end{verbatim}
\subsection{{\tt PART\_TNS.RED}}
Cette partie du logiciel contient les tenseurs particuliers connus du 
syst\`eme. En effet, si l'utilisateur peut d\'efinir ses propres tenseurs,
les moyens dont il dispose pour ce faire sont limit\'es par le fait qu'il 
peut seulement les particulariser en utilisant les r\`egles et quelques 
commandes g\'en\'erales (propri\'et\'es de sym\'etrie par exemple). Il existe
un certain nombres de tenseurs invariants ou de tenseurs g\'en\'eriques dont
la fr\'equence d'utilisation est telle qu'une programmation plus fine et plus
efficace se justifie. Jusqu'\`a pr\'esent, les tenseurs particuliers connus 
du syst\`eme sont:
\begin{list}{-}{\parsep 0in \itemsep 1pt}     
\item le tenseur {\tt delta},
\item le tenseur {\tt epsilon},
\item le tenseur delta g\'en\'eralis\'e {\tt del},
\item le tenseur de Minkowski {\tt eta},
\item le tenseur m\'etrique {\tt metric} g\'en\'erique.    
\end{list}
Les mots \'ecrits en caract\`eres ``machine \`a \'ecrire'' sont 
des {\em mots cl\'es} c'est-\`a-dire des symboles {\em r\'eserv\'es}.
L'existence de ces mots cl\'es permet \`a l'utilisateur de donner aux 
tenseurs ci-dessus les noms qu'il d\'esire. La fonction MAKE\_PARTIC\_TENS
permet d'activer ces tenseurs suivant la syntaxe
\begin{verbatim}
   make_partic_tens(<nom du tenseur> , <mot cl�>);
\end{verbatim}
Nous d\'ecrivons, ci-dessous, chacun de ces tenseurs.
\subsubsection{Le symbole de Kronecker}
Il travaille, \`a la fois dans un seul ou dans plusieurs espaces. 
Il est bloc-diagonal.
\begin{verbatim}
 % onespace est ON

   make_partic_tens(delt,delta); ==> t

   delt(a,b); ==> ***** bad choice of indices for DELTA tensor


   delt(a,-b); ==>

              a
          delt
              b

   delt(-a,b); ==>

              b
          delt
              a


   delt(-b,a); ==>

              a
          delt
              b

   
   wholespace_dim dim; ==> dim

   delt(1,-5); ==> 0


   delt(-a,a); ==> dim


   wholespace_dim 4; ==> 4

   delt(1,-5); ==> ***** numeric indices out of range


   wholespace_dim 3; ==> 3


   delt(-a,a); ==> 3
\end{verbatim}
On voit que les indices covariants et contravariants sont au m\^eme 
niveau. Que la sommation sur l'indice dummy {\tt a} est r\'ealis\'ee 
et s'adapte automatiquement \`a la dimension de l'espace, Que si la 
dimension est enti\`ere, le syst\`eme v\'erifie si les indices 
num\'eriques sont compatibles avec la dimension d\'eclar\'ee de l'espace. 
Maintenant, nous allons travailler dans plusieurs espaces.
Nous continuons la d\'emonstration pr\'ec\'edente~:
\begin{verbatim}
   off onespace;

   delt(a,-b); ==> 

              a
          delt
              b  

   delt(a,-a); ==> 3

   make_tensor_belong_space(delt,wholespace);

   define_spaces wholespace={5,signature=1}; ==> t

   delt(a,-a); ==> 5

   delt(0,-0); ==>1

   wholespace_dim ?; ==> 5


   rem_spaces wholespace; ==> t

   define_spaces wholespace={5,signature=0}; ==> t

   delt(a,-a); ==> 5

   delt(0,-a); ==> ***** bad value of indices for DELTA tensor

\end{verbatim}
En effet, en \index{ONESPACE} OFF ONESPACE, la d\'efinition de l'espace global
prend le pas sur la d\'efinition par d\'efaut. 
Pour que l'on acqui\`ere un cotr\^ole complet sur les indices, il faut 
d\'eclarer explicitement que {\tt delt} appartient \`a un espace ou a 
un sous-espace en utilisant \index{MAKE\_TENSOR\_BELONG\_SPACE}
MAKE\_TENSOR\_BELONG\_SPACE. 
Maintenant, nous allons mettre en \'evidence la propr\'et\'e bloc-diagonale
du tenseur {\tt delta} tout en illustrant d'autres commandes d\'ej\`a 
introduites.
\begin{verbatim}
   onespace ?; ==> no

   rem_spaces wholespace; ==> t


   define_spaces wholespace={10,signature=1}; ==> t


   wholespace_dim ?; ==> 11


   delt(a,-b); ==> 

              a
          delt
              b 


   define_spaces d1={5,euclidian}; ==> t

   define_spaces d2={2,euclidian}; ==> t


   mk_ids_belong_space({a},d1); ==> t

   mk_ids_belong_space({b},d2); ==> t


   delt(c,-b); ==>

              c
          delt
              b

   delt(c,-c); ==> 10

   delt(b,-b); ==> 2

   delt(a,-a); ==> 5


   delt(a,-b); ==> 0
\end{verbatim}
Si l'on veut retravailler dans un espace unique apr\`es avoir travaill\'e 
dans plusieurs espaces, il faut proc\'eder ad\'equatement.
Il est {\bf n\'ecessaire} de supprimer tous les espaces 
d\'efinis, avant de r\'ealiser la commande ON \index{ONESPACE}ONESPACE. 
\begin{verbatim}
   rem_spaces wholespace,d2,d1; ==> t

   show_spaces(); ==> {}

   make_tensor_belong_anyspace delt; ==> t

   on onespace; 

   wholespace_dim ?; dim

   delt(b,-b); ==> dim 
\end{verbatim}
On revient \`a l'\'etat initial du syst\`eme. L'espace est euclidien et 
de dimension ind\'etermin\'ee {\tt dim}. Celle-ci peut \^etre 
modifi\'ee par la fonction \index{WHOLESPACE\_DIM}WHOLESPACE\_DIM comme il 
a d\'ej\`a \'et\'e expliqu\'e.
\subsubsection{Le tenseur de Minkowski}
Ce tenseur correspond au mot cl\'e {\tt eta}. Il est toujours diagonal
et valide pour un ou plusieurs espaces. 

Quand l'option d'un seul espace est choisie, il est n\'ecessaire que sa 
signature soit \'egale \`a 1. Si ce n'est pas le cas, on obtient un 
signal d'avertissement et le tenseur est \'evalu\'e \`a 0.
\begin{verbatim}
   make_partic_tens(et,eta); ==> t

   signature 0; ==> 0;

   et(-b,-a); ==> ***  signature must be equal to 1 for ETA tensor

                   0
   
   signature 1; ==> 1

   et(-b,-a); ==> 

          et
            a b 

   et(a,-a); ==> dim 
\end{verbatim}
Le tenseur poss\`ede la propri\'et\'e de sym\'etrie et la sommation des 
indices donne bien la valeur d\'esir\'ee quelle que soit la dimension de
l'espace.

Les \'el\'ements diagonaux du tenseur d\'ependent de la convention choisie
 (celle des physiciens des hautes \'energies par d\'efaut)~:
\begin{verbatim}
   global_sign ?; ==> 1

   et(0,0); ==> 1

   et(3,3); ==>  - 1

   global_sign(-1);

   et(0,0); ==>  - 1

   et(3,3); ==> 1
\end{verbatim}
Comme pour tous les tenseurs, si la dimension de l'espace est un nombre,
les indices num\'eriques ne peuvent sortir de l'espace
\begin{verbatim}
   wholespace_dim 4; ==> 4

   et(a,-a); ==> 4

   et(5,5); ==> ***** numeric indices out of range    
\end{verbatim}
Il  faut noter que si le tenseur delta n'a pas \'et\'e pr\'ealablement 
d\'efini, on va r\'ecolter le message d'erreur {\tt *****  no name found for (delta)}
si l'on entre {\tt et(a,-a)}. Ceci est d\^u au fait que la simplification 
du tenseur ETA  repose, quand c'est possible, sur celle du tenseur DELTA.

Comment peut-on, utiliser le tenseur ETA en OFF ONESPACE~? 

Il faut d\'efinir l'espace auxquel il appartient. Par d\'efaut, il appartient
\`a l'espace total. Si celui-ci n'est pas d\'efini ou s'il est d\'eclar\'e 
euclidien, on obtient un message d'erreur. 
\begin{verbatim}
   et(a,b); ==> *** signature must be defined equal to 1 for ETA tensor
\end{verbatim}
On d\'eclare l'espace total et l'appartenance de ETA \`a cet espace: 
\begin{verbatim}
   define_spaces wholespace={4,signature=1}; ==> t  

   make_tensor_belong_space(et,wholespace); ==> wholespace

   et(a,b); ==>

            a b
          et

   et(a,-a); ==> 4
\end{verbatim}
Par d\'efaut, les indices appartiennent \`a tout l'espace. Par cons\'equent,
il n'est pas n\'ecessaire de d\'eclarer leur appartenance \`a cet espace.
Il en est autrement si l'espace auxquel ETA appartient est un sous-espace
car, dans ce cas, la sommation sur les indices n'est d\'efinie que si 
l'indice muet appartient au sous-espace. 
\begin{verbatim}
   make_tensor_belong_anyspace et; ==> t

   rem_spaces wholespace; ==> t

   define_spaces wholespace={8,signature=1}; ==> t

   define_spaces mink={5,signature=1}; ==> t

   make_tensor_belong_space(et,mink); ==> mink

   et(a,b); ==> 

            a b
          et

   et(a,-a); ==> 8
\end{verbatim}
Le syst\`eme a donc consid\'er\'e que {\tt et}  est d\'efini dans tout 
l'espace malgr\'e que l'utilisateur dit qu'il n'appartient qu' au 
sous-espace {\tt mink}. Pour que la sommation soit correcte, il faut 
que {\tt a} soit d\'eclar\'e dans l'espace {\tt mink}~:
\begin{verbatim}
   mk_ids_belong_space({a},mink); ==> t

   et(a,-a); ==>  5    
\end{verbatim}
\subsubsection{Les tenseurs epsilon}
Lorsque l'on manipule un seul espace, le tenseur epsilon que l'on d\'ef\'enit
par \index{MAKE\_PARTIC\_TENS} MAKE\_PARTIC\_TENS est plac\'e dans un espace 
euclidien si la signature est nulle. 
Il est plac\'e dans un espace du type Minkowski si la 
signature est \'egale \`a 1. Pour les signatures plus \'elev\'ees, il n'est 
pas construit. 
Si la dimension de l'espace est symbolique, le nombre d'indices
qu'il poss\`ede est {\em arbitraire}. Il admet \`a la fois des indices 
covariants et contravariants. Quand les deux sont pr\'esents et 
{\em seulement dans ce cas}, la position
respective des indices covariants, d'une part, et contravariants, d'autre 
part {\em n'est pas modifi\'ee} par rapport \`a l'input. 
\begin{verbatim}
   make_partic_tens(eps,epsilon); ==> t
 
   eps(a,d,b,-c,e); ==>

                a d b e
           - eps
                        c  

   eps(a,d,b,-g,e,-f); ==>

                a d b e
           - eps
                        g f

   eps(a,d,b,-f,e,-f); ==> 0
\end{verbatim}
Quand les indices sont tous covariants ou contravariants, l'antisym\'etrie
est compl\`etement exploit\'ee.
\begin{verbatim}
   eps(-b,-a); ==>

           - eps
                a b


   signature ?; ==> 0

   eps(1,2,3,4); ==> 1

   eps(-1,-2,-3,-4); ==> 1

   wholespace_dim 3; ==> 3

   eps(-1,-2,-3); ==> 1

   eps(-1,-2,-3,-4); ==> ***** numeric indices out of range

   eps(-1,-2,-3,-3); ==> ***** bad number of indices for  (eps)  tensor

   eps(a,b); ==> ***** bad number of indices for  (eps)  tensor

   eps(a,b,c); ==> 

             a b c
          eps

   eps(a,b,b); ==> 0

   signature 1; ==> 1

   eps(0,1,2); ==> 

             0 1 2
          eps

   eps(-0,-1,-2); ==>

             0 1 2
          eps

   wholespace_dim 4; ==> 4

   eps(0,1,2,3); ==>

             0 1 2 3
          eps

   eps(-0,-1,-2,-3); ==>

                0 1 2 3
           - eps

   global_sign(-1);

   wholespace_dim 3; ==> 3

   eps(-0,-1,-2); ==>

                0 1 2
           - eps

\end{verbatim}
Lorsque l'on travaille dans plusieurs espaces, le syt\`eme permet 
d'introduire plusieurs tenseurs du type 'epsilon'. Ces tenseurs {\em doivent} 
alors \^etre associ\'es \`a un espace d\'efini par DEFINE\_SPACES pour que 
le logiciel travaille correctement lorsque l'on utilise CANONICAL. 
On peut voir quels sont les tenseurs du type 'epsilon' qui ont \'et\'e 
d\'efinis et dans quel espace ils travaillent en utilisant le 
fonction SHOW\_EPSILONS qui ne prend pas  d'arguments.
Attention ! cette fonction ne donne pas le tenseur du type 'epsilon' 
que l'on peut d\'efinir en ON ONESPACE. En effet, l'espace par d\'efaut
ne poss\`ede aucun nom.  
Partant d'un environnement frais, on a :
\begin{verbatim}
   show_epsilons(); ==> {}

   onespace ?; ==> yes

   make_partic_tens(eps,epsilon); ==>t

   show_epsilons(); ==> {}
\end{verbatim}
Si on a d\'ej\`a d\'efini un tenseur epsilon en ON onespace, alors,
pour qu'il soit ``visible'', il faut l'associer \`a un espace correctement
d\'efini. par exemple~:  
\begin{verbatim}
   define_spaces wholespace={7,signature=1}; ==> t

   show_epsilons(); ==> {}   % toujours invisible

   make_tensor_belong_space(eps,wholespace); ==> wholespace

   show_epsilons(); ==> {{eps,wholespace}}
\end{verbatim}
Bien qu'il soit maintenant attach\'e \`a un espace, si on d\'ecide de 
retravailler en ON ONESPACE, ses propri\'et\'es ne d\'ependrons, de 
nouveau, que de l'espace par d\'efaut. Bien entendu, cet espace poss\`ede
maintenant la dimension 7 et la signature +1 fix\'ee par la commande
{\index DEFINE\_SPACES}DEFINE\_SPACES.

Si l'on d\'esire introduire plusieurs tenseurs de ce type, on doit 
\'evidemment travailler dans plusieurs espaces. Le tenseur d\'ej\`a 
d\'efini reste disponible~:
\begin{verbatim}
    off onespace;

    eps(a,b,c); ==>

             a b c
          eps
\end{verbatim}
Il est naturel d'associer ce tenseur \`a un espace. Supposons que ce soit 
\`a {\tt wholespace}. Voici comment on proc\`ede~:
\begin{verbatim}
   define_spaces wholespace={dim,signature=1}; ==> t

   make_tensor_belong_space(eps,wholespace); ==> wholespace

   show_epsilons(); ==> {{eps,wholespace}}

   eps(0,1,2,3); ==>

             0 1 2 3
          eps


   eps(-0,-1,-2,-3); ==>

                0 1 2 3
           - eps


   eps(0,1,2); ==>

             0 1 2
          eps

   eps(-0,-1,-2); ==>

             0 1 2
          eps 
\end{verbatim}
 On voit que le nombre 
d'indices du tenseur ainsi d\'efini est quelconque. Ceci est d\^u au 
fait que la dimension de l'espace est ind\'etermin\'ee ({\tt dim}).
Quand on veut introduire plusieurs tenseurs epsilon, le plus souvent
c'est que l'on manipule deux espaces produit direct l'un de l'autre.
Par exemple, l'espace de Minkowski et l'espace couleur dans QCD.
Si l'on veut maintenant introduire un second tenseur 'epsilon', on 
commence par introduire un sous-espace, puis on le d\'efini.
\begin{verbatim}
   define_spaces eucl={3,euclidian}; ==> t

   make_partic_tens(ep,epsilon); ==> *** Warning: ep MUST belong to a space
                                     t

   make_tensor_belong_space(ep,eucl); ==> eucl


   show_epsilons(); ==> {{ep,eucl},{eps,wholespace}}
  

   ep(-1,-2,-3); ==> 1

   ep(1,2,3); ==> 1

   ep(a,b,c,d); ==> ***** bad number of indices for  (ep)  tensor

   ep(1,2,4); ==> ***** numeric indices out of range  
\end{verbatim}
Le tenseur {\tt ep} est une restriction au sous-espace euclidien de 
{\tt wholespace} mais s'il poss\`ede 3 indices dont certains sont 
symboliques, le syst\`eme ne peut savoir \`a quel espace les 
indices appartiennent. C'est pourquoi, il est n\'ecessaire de 
de d\'eclarer leur appartenance. Voici une illustration:
\begin{verbatim}
   mk_ids_belong_space({e1,e2,e3},eucl); ==> t

   mk_ids_belong_space({a,b,c},wholespace); ==> t

   ep(e1,e2,e3); ==>

            e1 e2 e3
          ep

   ep(e1,e2,z); ==>

            e1 e2 z
          ep

   ep(e1,e2,a);==>  ***** some indices are not in the space of ep


   eps(a,b,c); ==>

             a b c
          eps
\end{verbatim}
Dans l'exemple ci-dessus, {\tt wholespace} poss\`ede une dimension 
symbolique ce qui explique que le dernier exemple ne donne pas un message
d'erreur.
Si on introduit une dimension num\'erique, il en va tout autrement. Par exemple,
l'exemple suivant suppose que {\tt wholespace} poss\`ede une dimension  7.
\begin{verbatim}
   show_spaces(); ==>

          {{wholespace,7,signature=1},

           {eucl,3,signature=0}}

   eps(e1,e2,e3); ==> ***** bad number of indices for  (eps)  tensor

   eps(e1,e2,e3,e,f,g,h); ==>

                e e1 e2 e3 f g h
           - eps
\end{verbatim}
On peut aussi d\'efinir des fonctions epsilon sur deux espaces disjoints.
Dans l'exemple suivant, on \'elimine {\tt wholespace} et on introduit un
espace de Minkowski. Puis on r\'eassigne le tenseur {\tt eps} \`a ce 
nouvel espace. Il faut noter que l'on n'a pas besoin ni de red\'efinir 
{\tt eps} ni d'enlever son appartenance \`a l'espace {\tt wholespace}.
Dans l'exemple, ceci est fait pour mieux illustrer le fonctionnement des 
diverses commandes. On enl\`eve aussi l'appartenance des indices {\tt a,b,c} 
\`a {\tt wholespace}. Notons que les indices {\tt e1,e2,e3} appartiennent 
\`a l'espace {\tt eucl} comme dans l'exemple pr\'ec\'edent.
\begin{verbatim} 
   rem_spaces wholespace; ==> t

   make_tensor_belong_anyspace eps; ==> t

   show_epsilons(); ==> {{ep,eucl}}

   show_spaces(); ==> {{eucl,3,signature=0}}

   mk_ids_belong_anyspace a,b,c; ==> t

   define_spaces mink={4,signature=1}; ==> t

   show_spaces(); ==>

          {{eucl,3,signature=0},

           {mink,4,signature=1}}

   make_tensor_belong_space(eps,mink); ==> mink

   show_epsilons(); ==> {{eps,mink},{ep,eucl}}

   eps(a,b,c,d); ==>

             a b c d
          eps

   eps(e1,b,c,d); ==> ***** some indices are not in the space of eps

   ep(e1,b,c,d); ==> ***** bad number of indices for  (ep)  tensor

   ep(e1,b,c); ==>

            b c e1
          ep


   ep(e1,e2,e3); ==> 

            e1 e2 e3
          ep 
\end{verbatim}
\subsubsection{Le tenseur m\'etrique g\'en\'erique}
Dans le cas o\`u l'on travaille dans le cadre d'une g\'eom\'etrie 
Riemannienne, il est utile d'introduire un tenseur m\'etrique g\'en\'erique.
Il est associ\'e au mot cl\'e {\ttindex METRIC}{\tt METRIC}.   
Ce tenseur peut d\'ependre {\em explicitement} de 1 ou plusieurs variables.
Lorsque les indices sont mixtes, il est identique \`a la fonction 
{\ttindex DELTA}{\tt DELTA}. 
Enfin, il est naturellement d\'efini pour l'espace entier, il est sym\'etrique
et il poss\`ede la propri\'et\'e d'\^etre bloc-diagonal. 
Pour le particulariser, on exploite les r\`egles.  
En particulier, le tenseur m\'etrique ainsi d\'efini peut 
\^etre le tenseur 'delta' de l'espace euclidien usuel.
\begin{verbatim}
   onespace ?; ==> yes
   
   g(a,b); ==>

           a b
          g

   g(b,a); ==>

           a b
          g

   g(a,b,c); ==> ***** bad choice of indices for a METRIC tensor

   g(-a,b); ==> *****  no name found for (delta)

   make_partic_tens(delt,delta); ==> t

   g(a,b,{x,y}); ==>

            a b
          g    (x,y)

   g(a,-b,{x,z}); ==>

              a
          delt
              b
   
   let g({x,y},1,1)=x*y;

   g({x,y},1,1); ==> x*y

   rem_value_tens g({x,y},1,1); 

   g({x,y},1,1); ==>

            1 1
          g    (x,y)
\end{verbatim}
\subsection{{\tt CANON.RED}}
\subsubsection{Les expressions tensorielles}
Jusqu'ici, nous avons d\'ecrit la construction et les 
propri\'et\'es des tenseurs g\'en\'eriques ou particuliers pris 
{\em individuellement}. Dans cette section, nous d\'ecrivons la 
manipulation des polyn\^omes de tenseurs.
On peut entrer un polyn\^ome arbitraire. Celui-ci peut non seulement 
contenir des grandeurs indic\'ees mais aussi des op\'erateurs au sens 
usuel (sin x, op(a,b,c), etc ...).
Par exemple :
\begin{verbatim}
   aa:= delt({x - y})*delt(a, - g)*delt(d, - g)*delt(g, -r)*
         
         eps( - d, - e, - f)*eps(a,b,c)*op(x,y) + 1; ==>

                                a      d      g
          aa := delt(x - y)*delt  *delt  *delt  *eps
                                g      g      r     d e f


                    a b c
                *eps     *op(x,y) + 1

\end{verbatim}
Dans cette expression, {\tt delt} et {\tt eps} sont les tenseurs 
delta et epsilon qui ont \'et\'e pr\'ealablement d\'efinis, {\tt delt(x-y)}
est la fonction delta de Dirac et op est un op\'erateur g\'en\'erique 
qui d\'epend des {\em variables} {\tt x} et {\tt y}.
Il est important de noter que cette expression n'est pas coh\'erente 
car les deux termes ne poss\`edent pas les m\^emes indices {\em libres} 
et, de plus, l'indice muet {\tt g} est pr\'esent 3 fois dans le 
premier terme.
En fait, seule la coh\'erence math\'ematique de chaque facteur est
v\'erifi\'ee. Sur cette expression, on peut effectuer toutes les 
op\'erations de manipulation du syst\`eme. Seules, les sommations 
sur les indices qui appartiennent \`a un unique seront r\'ealis\'ees 
toutes les fois qu'il est possible. Ainsi :
\begin{verbatim}
   sub(g=a,aa); ==>

                          a      d              a b c
          delt(x - y)*delt  *delt  *eps     *eps     *op(x,y)*dim + 1
                          r      a     d e f

\end{verbatim}
{\tt g} \`a \'et\'e remplac\'e par {\tt a} et la sommation sur un 
des tenseurs delta a \'et\'e faite.
De nouveau, la coh\'erence au niveau de la variance n'a pas \'et\'e 
faite.
Pour pouvoir r\'eellement manipuler proprement cette expression, il 
faut utiliser la fonction \index{CANONICAL}CANONICAL.
\subsection{L'utilisation de CANONICAL}
La fonction \index{CANONICAL}CANONICAL est une extension de la fonction 
du m\^eme nom du logiciel {\tt DUMMY}. Comme elle, elle peut manipuler 
des polyn\^omes d'op\'erateurs ayant des sym\'etries diverses mais, en 
plus,  
\begin{enumerate}
\item elle v\'erifie la coh\'erence des sommations sur les indices 
tensoriels muets et celle des indices libres;
\item elle effectue les sommations tensorielles sur les produits de 
tenseurs toutes les fois que c'est possible car elle reconna\^\i t les 
tenseurs particuliers;
\item elle recherche une forme normale des diff\'erents termes du polyn\^ome 
en vue de maximaliser les simplifications et donne, de ce fait, une 
forme normale \`a l'expression polynomiale qui est entr\'ee;
\item elle fonctionne aussi dans le cas o\`u des d\'eriv\'ees formelles 
de tenseurs ou d'op\'erateurs se pr\'esentent (ce qui n'\'etait pas le 
cas pour l'ancienne version de CANONICAL);
\item elle est capable de travailler dans plusieurs (sous)-espaces.
\end{enumerate}
Nous d\'ecrivons, successivement, ces diverses capacit\'es de CANONICAL.
\subsubsection{Coh\'erence des indices tensoriels}
Nous travaillons dans un seul espace et l'indice {\tt a} a d\'ej\`a 
\'et\'e utilis\'e comme indice muet pour le tenseur delta. 
\begin{verbatim}
   tensor te,tf; ==> t

   dummy_indices(); ==> {a}

   bb:=te(a,b,b)*te(-b); ==>

                      a b b
          bb := te *te
                  b


   canonical bb; ==> ***** ((b) (a b b)) are inconsistent lists of indices


   bb:=te(a,b,a)*te(-a); ==> ***** (nil (a b a)) are inconsistent lists of indices

   aa:=te(a,-c)*tf(a,-c); ==>

                  a     a
          aa := te   *tf
                    c     c

   canonical aa; ==> ***** wrong use of indices ((minus c) a)

   aa:=te(b,-c)*tf(b,-c); ==>

                  b     b
          aa := te   *tf
                    c     c

   canonical aa; ==>

            b     b
          te   *tf
              c     c
\end{verbatim}
Dans le premier cas, c'est canonical qui donne le message d'erreur et 
l'on voit dans le message que l'ensemble des indices sont consid\'er\'es.
La premi\`ere sous-liste indique que l'indice muet {\tt b} a \'et\'e 
d\'etect\'e.
Dans le second cas, bien que le message soit formellement semblable, il 
a une autre interpr\'etation~: le syst\`eme sait que {\tt a} est un 
indice muet. Or, il appara\^\i t 2 fois comme indice contravariant 
dans le {\em premier facteur} {\tt te}. Ce fait est mis en \'evidence par la 
liste des indices contravariants donn\'ee dans le message. Ici, la liste des 
indices covariants est nil.  
Dans le troisi\`eme cas, l'indice muet {\tt a} n'appara\^\i t qu'une fois 
dans chaque tenseur. Cependant, comme dans le contexte, il a \'et\'e 
utilis\'e comme indice muet, CANONICAL n'admet pas qu'il soit utilis\'e
ult\'erieurement comme indice {\em libre}.
Dans le quatri\`eme cas, il n'y a pas de probl\`eme puisque {\tt b} et 
{\tt c} sont tous les deux des indices {\em libres}.

CANONICAL v\'erifie que, dans un polyn\^ome, tous les termes poss\`edent 
la m\^eme variance.
\begin{verbatim}
   aa:=te(a,c)+x^2; ==>

                  a c    2
          aa := te    + x

   canonical aa; ==> ***** scalar added with tensor(s)

   aa:=te(a,b)+tf(a,c); ==>

                  a b     a c
          aa := te    + tf

   canonical aa; ==> ***** mismatch in free indices :  ((a c) (a b))
\end{verbatim}
La contrainte sur la pr\'esence des indices covariants et contravariants 
n'existe pas si ces indices apparaissent dans des operateurs g\'en\'eriques.
\begin{verbatim}
   dummy_names b; ==> t

   cc:=op(b)*op(a,b,b); ==> cc := op(a,b,b)*op(b)

   canonical cc; ==> op(a,b,b)*op(b)    

   clear_dummy_names;
\end{verbatim}
Toute les fois que c'est possible les indices muets contravariants d'un 
tenseur qui (par d\'efaut) appartient \`a un espace m\'etrique sont 
plac\'es {\em avant} des indices covariants de m\^eme nom. 
Ainsi:
\begin{verbatim}
   pp:=te(a,-a)+te(-a,a)+1; ==> 

                    a     a
          pp := te    + te    + 1
                  a         a

   canonical pp; ==>

              a
          2*te    + 1
                a

   pp:=te(a,-a)+te(-b,b); ==>

                    b     a
          pp := te    + te
                  b         a

   canonical pp; ==> 

              a
          2*te
                a

     pp:=te(r,a,c,d,-a,f)+te(r,-b,c,d,b,f); ==>

                    r   c d b f     r a c d   f
            pp := te            + te
                      b                     a


   canonical pp; ==>


              r a c d   f
          2*te
                      a

\end{verbatim}
Il existe un cas pour lequel cette transformation ne produit pas 
une forme normale ed\'equate. Appliquant CANONICAL sur l'expression 
ne permet jamais de l'annuller~!  Le voici~:
\begin{verbatim}
   tensor nt; ==> t

   a1:=nt(-a,d)*nt(-c,a); ==>

              d     a
          nt   *nt
            a     c


   a2:=nt(-c,-a)*nt(a,d); ==>

                  a d
          nt   *nt
            c a


   a12:=a1-a2; ==> 

                     d     a           a d
          a12 := nt   *nt    - nt   *nt
                   a     c       c a


   canonical a12; ==>

                 d     a           a d
           - nt   *nt    + nt   *nt
               a     c       c a


   a1 -canonical a2; ==> 0

   canonical a1 - a2; ==> 0
\end{verbatim}
Cette simplification n'est pas op\'erante si le tenseur appartient \`a 
un espace AFFINE.
Partant de l'objet {\tt pp} introduit dans l'exemple pr\'ec\'edent,
\begin{verbatim}
   off onespace;

   define_spaces aff={dd,affine}; ==> t

   make_tensor_belong_space(te,aff); ==> aff

   mk_ids_belong_space({a,b},aff); ==> t

   canonical pp;

            r   c d a f     r a c d   f
          te            + te
              a                     a
\end{verbatim}
L'indice {\tt b} est devenu l'indice {\tt a} mais les positions 
sont rest\'ees les m\^emes.
Pour remettre le syst\`eme dans l'\'etat initial on r\'ealise 
les commandes:
\begin{verbatim}
   make_tensor_belong_anyspace te; ==> t

   mk_ids_belong_anyspace a,b; ==> t

   on onespace;

   canonical pp; ==>

              r a c d   f
          2*te
                      a

\end{verbatim}
\subsubsection{La sommation sur les tenseurs particuliers}
\begin{center} 
Le cas du tenseur {\tt DELTA}
\end{center}
Comme pour les tenseurs g\'en\'eriques, la validit\'e de 
l'expression tensorielle est test\'ee :
\begin{verbatim}
   aa:=delta(a,-b)+delta(a,-c); ==>

                     a         a
          aa := delta   + delta
                     b         c

   canonical aa; ==> ***** mismatch in free indices
\end{verbatim}
Canonical r\'ealise les sommations toutes les fois que c'est possible.
\begin{verbatim}
   aa:=delta(a,-b)*delta(b,-c)*delta(c,-a) + 1; ==>

                     a       b       c
          aa := delta  *delta  *delta   + 1
                     b       c       a

   canonical aa; ==> dim + 1

   aa:=delta(a,-b)*delta(b,-c)*delta(c,-d)*te(d,e)$

   canonical aa; ==> 

            a e
          te
\end{verbatim}
Attention ! le syst\`eme refuse de contracter des expressions
contenant des {\em indices} utilis\'es dans des operateurs. Ceci, 
pour des raisons de consistance~:
\begin{verbatim}
   operator op;

   aa:=delta(a,-b)*op(b,b)$

   canonical aa; ==>

               a
          delta  *op(b,b)
               b

   dummy_names b; ==> t

   canonical aa; ==>


               a
          delta  *op(b,b)
               b
\end{verbatim}
De fait, si dans l'exemple ci-dessus, la contraction se faisait, on devrait
pouvoir introduire la m\^eme expression avec l'indice {\tt b} remplac\'e 
par l'indice {\tt c}. La diff\'erence donnerait {\tt 0} alors que 
l'expression tensorielle de la diff\'erence est visiblement inconsistante.
\begin{verbatim}
   bb:=delta(a,-c)*op(c,c); ==> 

                     a
          bb := delta  *op(c,c)
                     c

   canonical(aa-bb); ==> ***** mismatch in free indices 
\end{verbatim}
Pour manipuler de telles expressions, il {\em faut} d\'eclarer {\tt op}
comme tenseur.
\begin{center} 
Le cas du tenseur {\tt ETA}
\end{center}
\begin{verbatim}
   make_partic_tens(eta,eta); ==> t
   
   aa:=delta(a,-b)*eta(b,c); ==> 

             *****  signature must be defined equal to 1 for ETA tensor

   signature 1; ==> 1

   aa:=delta(a,-b)*eta(b,c); ==> 

                     a     b c
          aa := delta  *eta
                     b

   canonical aa; ==> 

             a c
          eta


   canonical(eta(a,b)*eta(-b,c)); ==>

             a c
          eta


   canonical(eta(a,b)*eta(-b,-c)); ==>

               a
          delta
               c

   canonical(eta(a,b)*eta(-b,-a)); ==> dim

   canonical (eta(-a,-b)*te(d,-e,f,b)); ==>

            d   f
          te
              e   a


   aa:=eta(a,b)*eta(-b,-c)*te(-a,c)+1; ==>

                          a b     c
          aa := eta   *eta   *te    + 1
                   b c          a

   canonical aa; ==>

            a
          te    + 1
              a

   aa:=eta(a,b)*eta(-b,-c)*delta(-a,c)+1+eta(a,b)*eta(-b,-c)*te(-a,c); ==>

                     c            a b             a b     c
          aa := delta  *eta   *eta    + eta   *eta   *te    + 1
                     a     b c             b c          a



   canonical aa; ==> 

            a
          te    + dim + 1
              a
\end{verbatim}
Nous pouvons y ajouter un tenseur m\'etrique g\'en\'erique~:
\begin{verbatim}
   aa:=g(a,b)*g(-b,-d); ==>

                      a b
          aa := g   *g
                 b d

   canonical aa; ==>

               a
          delta
               d

   aa:=g(a,b)*g(c,d)*eta(-c,-e)*eta(e,f)*te(-f,g); ==>

                          e f  a b  c d     g
          aa := eta   *eta   *g   *g   *te
                   c e                    f

   canonical aa; ==>

           a b   d g
          g   *te

\end{verbatim}
Enfin, on peut aussi consid\'erer des expressions tensorielles 
contenant le tenseur epsilon. Nous choisissons la signature 1. 
Il en r\'esulte que le produit de deux tenseurs epsilon donne 
*moins* la fonction delta g\'en\'eralis\'ee correspondante.
\begin{verbatim}
   wholespace_dim dim; ==> dim
  
   make_partic_tens(gd,del); ==> t

   rem_dummy_indices a; ==> t

   signature 1; ==> 1

   aa:=eps(a,b)*eps(-c,-d); ==>

                          a b
          aa := eps   *eps
                   c d

   canonical aa; ==>

               a b
           - gd
               c d


   aa:=eps(a,b)*eps(-a,-b); ==>

                          a b
          aa := eps   *eps
                   a b

   canonical aa; ==> dim*( - dim + 1)

   on exdelt;

   gd(-a,-b,a,b); ==> dim*(dim - 1)

   aa:=eps(a,b,c)*eps(-b,-d,-e); ==>

                            a b c
          aa := eps     *eps
                   b d e

   canonical aa; ==>

               a       c               a       c         a       c
          delta  *delta  *dim - 2*delta  *delta   - delta  *delta  *dim
               d       e               d       e         e       d

                    a       c
           + 2*delta  *delta
                    e       d

\end{verbatim}
Various expressions containing the epsilon tensor are considered below.
Notice that CANONICAL takes care of the symmetries of the various tensors.
\begin{verbatim}
   aa:=eps( - b, - c)*eta(a,b)*eta(a,c); ==>


                    a b    a c
          eps   *eta   *eta
             b c

   canonical aa; ==> 0


   aa:=eps(a,b,c)*te(-a)*te(-b); ==>

                   a b c
          aa := eps     *te *te
                           a   b

   canonical aa; ==> 0

   tensor tf,tg;

   aa:=eps(a,b,c)*te(-a)*tf(-b)*tg(-c)+eps(d,e,f)*te(-d)*tf(-e)*tg(-f); ==>

                   a b c                  d e f
          aa := eps     *te *tf *tg  + eps     *te *tf *tg
                           a   b   c              d   e   f

   canonical aa; ==>

               a b c
          2*eps     *te *tf *tg
                       a   b   c

   aa:=eps(a,b,c)*te(-a)*tf(-c)*tg(-b)+eps(d,e,f)*te(-d)*tf(-e)*tg(-f)$

   canonical aa; ==> 0
\end{verbatim}
\index{CANONICAL}CANONICAL peut aussi travailler dans {\em plusieurs} 
espaces.  Voici une illustration dans laquelle nous d\'efinissons 
deux tenseurs epsilon, l'un dans l'espace global, l'autre dans un 
sous-espace. L'introduction de la fonction delta g\'en\'eralis\'ee 
tient compte de cette situation.
\begin{verbatim}
   off onespace;

   define_spaces wholespace={dim,signature=1}; ==> t

   define_spaces subspace={3,signature=0}; ==> t

   show_spaces(); ==>

          {{wholespace,dim,signature=1},

           {subspace,3,signature=0}}

   
   make_partic_tens(kap,epsilon); ==> t

   make_tensor_belong_space(eps,wholespace); ==> wholespace

   make_tensor_belong_space(kap,subspace); ==> subspace

   show_epsilons(); ==> {{eps,wholespace},{kap,subspace}}

   off exdelt;

   aa:=kap(a,b,c)*kap(-d,-e,-f)*eps(i,j)*eps(-k,-l); ==>

                          i j             a b c
          aa := eps   *eps   *kap     *kap
                   k l           d e f

   canonical aa; ==>

               a b c    i j
           - gd      *gd
               d e f    k l

\end{verbatim}
Avec les commandes ci-dessus, si l'on veut extraire les tenseurs 
delta et contracter les indices dans les espaces d\'efinis, il est 
{\em n\'ecessaire} de dire au syst\`eme que les indices {\tt a,b,c,d,e,f}
appartiennent \`a l'espace global tandis que les indices {\tt i,j,k,l}
appartiennent au sous-espace que nous avons appel\'e {\tt subspace}.
Sans ces d\'eclarations, le r\'esultat serait incorrecte.
\begin{verbatim}
   mk_ids_belong_space({a,b,c,d,e,f},wholespace}; ==> t
  
   mk_ids_belong_space({i,j,k,l},subspace); ==> t
  
   sub(d=a,e=b,k=i,aa); ==>

                 c       j         2
          2*delta  *delta  *( - dim  + 3*dim - 2)
                 f       l
\end{verbatim}
\begin{center}
Les tenseurs qui poss\`edent une sym\'etrie partielle
\end{center}
Dans le logiciel {\tt DUMMY}, la commande \index{SYMTREE}SYMTREE 
permet d'imposer \`a un op\'erateur une sym\'etrie partielle.
L'action de cette commande \`a \'et\'e \'etendue aux tenseurs 
g\'en\'eriques. Voici l'exemple du tenseur de Riemann~:
\begin{verbatim}
   tensor r; ==> t

   symtree(r,{!+,{!-,1,2},{!-,3,4}});

   ra:=r(b,a,c,d); ==>

                 b a c d
          ra := r

   canonical ra; ==>

              a b c d
           - r

   ra:=r(c,d,a,b); ==>

                 c d a b
          ra := r

   canonical ra; ==>

           a b c d
          r


   canonical r(-c,-d,-a,-b); ==>

          r
           a b c d

   canonical r(-c,-d,a,b); ==>

           a b
          r
               c d

   r(-c,-c,a,b); ==>  0



   ra:=r(-c,-d,c,b); ==>

                     c b
          ra := r
                 c d

   canonical ra; ==>

              b c
           - r
                  c d
\end{verbatim}
Comme l'avant derni\`ere illustration le montre, lorsque, pour raison 
de sym\'etrie, la composante du tenseur est nulle, elle s'annulle 
effectivement {\em avant} l'action de CANONICAL. 
Il y a pr\'esentement une restriction importante sur l'utilisation de 
SYMTREE. Cette restriction est celle que l'on trouve aussi dans le 
logiciel DUMMY. La suite des entiers utilis\'es doit \^etre la suite 
naturelle. Elle ne peut contenir ni entiers manquants ni inversions 
 arithm\'etique. Par exemple, on {\em ne peut pas} introduire
\begin{verbatim}
   symtree(r,{!*,{!+,1,3},{!*,2,4}});

   symtree(r,{!*,{!+,1,2},{!*,4,5}};

   symtree(r,{!*,{!-,1,3},{!*,2}});
\end{verbatim}
Les commandes SYMTREE les plus proches de celles ci-dessus que l'on 
puisse introduire sont:
\begin{verbatim}
   symtree(r,{!*,{!+,1,2},{!*,3,4}});

   symtree(r,{!*,{!+,1,2},{!*,3,4,5}};

   symtree(r,{!*,{!-,1,2},{!*,3}});
\end{verbatim}
Lorsqu'une expression n'a pas de sym\'etrie, il est fr\'equent de la 
sym\'etriser d'une mani\`ere ou d'une autre.
La fonction \index{SYMMETRIZE}SYMMETRIZE du logiciel {\tt ASSIST} a \'et\'e
g\'en\'eralis\'ee et am\'elior\'ee.
Pour tout noyau (qui peut \^etre un tenseur ou un op\'erateur),
cette fonction g\'en\`ere automatiquement 
\begin{enumerate}
\item la somme sur les permutations cycliques des indices,
\item la somme sym\'etrique ou antisym\'etrique sur les permutations
des indices.
\end{enumerate}
En outre, si on lui donne une liste d'indices, elle g\'en\`ere une 
liste qui contient les permutations (cycliques) de ces indices.
Cette fonction n'est pas encore applicable aux tenseurs qui d\'ependent 
{\em explicitement} de variables.  
Voici des illustrations de son fonctionnement.
\begin{verbatim}
   symmetrize(te(x,y,z),te,cyclicpermlist); ==>

            x y z     y z x     z x y
          te      + te      + te


   symmetrize(te(x,y),te,permutations); ==>

            x y     y x
          te    + te

   symmetrize(te(x,y),te,permutations,perm_sign); ==>

            x y     y x
          te    - te

   symmetrize(te(y,x),te,permutations,perm_sign); ==>

               x y     y x
           - te    + te
\end{verbatim}
Cette fonction n'est pas valable pour une expression qui n'est pas 
un noyau. Si l'on doit ``sym\'etriser'' une telle expression, voici
comment on peut proc\'eder. dans l'exemple, {\tt te, te1} ont \'et\'e 
d\'eclarer tenseurs.~:
\begin{verbatim}
   ex:=te(a,-b,c)*te1(-a,-d,-e); ==>

                  a   c
          ex := te     *te1
                    b      a d e

   ll:=list(b,c,d,e)$


   lls:=symmetrize(ll,list,cyclicpermlist); ==>

          lls := {{b,c,d,e},{c,d,e,b},{d,e,b,c},{e,b,c,d}}

   excyc:=for each i in lls sum sub(b=i.1,c=i.2,d=i.3,e=i.4,ex);  ==>


                 a   c              a   d              a   e
      excyc := te     *te1      + te     *te1      + te     *te1
                   b      a d e       c      a e b       d      a b c

                        a   b
                    + te     *te1
                          e      a c d  
\end{verbatim}
Bien entendu, dans l'exemple ci-dessus, l'expression obtenue 
\begin{center}
CANONICAL et les d\'eriv\'ees des tenseurs
\end{center}
La d\'eriv\'ee covariante n'est pas (encore) directement d\'efinie. 
Cependant, la d\'eriv\'ee ordinaire l'est et la d\'eriv\'ee covariante 
peut, bien entendu, \^etre construite \`a partir d'elle.
Jusqu'ici, \index{CANONICAL}CANONICAL n'\'etait pas capable de 
rechercher la forme normale d'une expression plac\'ee sous l'op\'eration 
d\'eriv\'ee. Elle a donc \'et\'e ad\'equatement g\'en\'eralis\'ee pour 
que cette limitation disparaisse.
Les exemples suivants illustrent ses possibilit\'es.
\begin{verbatim}   
   tensor te,x; ==> t

   depend te,x;


   aa:=df(te(a,-b),x(b))-df(te(a,-c),x(c)); ==>

                     a              a
          aa := df(te   ,x ) - df(te   ,x )
                       b  b           c  c

   canonical aa; ==> 0


   make_partic_tens(eta,eta); ==>  t

   signature 1;

   aa:=aa*eta(-a,-d); ==>

                     b       a
          aa := delta  *df(te   ,x )*eta
                     c         b  c     a d

   canonical aa; ==>

                 a  a
          df(te   ,x )
               d

\end{verbatim}
Dans le dernier exemple, apr\`es les contractions tensorielles, on a 
\begin{verbatim}

                    
          df(te   ,x )
               d b  b

\end{verbatim}
Deux transformations se sont produites. La premi\`ere tient compte du 
fait que l'espace par d\'efaut est m\'etrique et, par cons\'equent, 
l'indice de sommation {\tt b} est transform\'e en indice contravariant
et son nom est chang\'e en {\tt a}.  
\end{document}



