/** \file TenseurQ.h
* Définition des tenseurs d'ordre 4: méthodes strictement virtuelles
*/


// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2021 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.



/************************************************************************
*     DATE:        2/5/2002                                            *
*                                                                $     *
*     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
*                                                                $     *
*     PROJET:      Herezh++                                            *
*                                                                $     *
************************************************************************
*     BUT:   Definir les tenseurs d'ordre 4 de differentes composantes.*
*            La classe est virtuelle pure.                             *
*            Elle se decline en fonction de la dimension du probleme   *
*            L'objectif principal est de surcharger les differentes    *
*            operations  classiques.                                   *
*                                                                $     *
*     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
************************************************************************/

#ifndef TENSEURQ_H
#define TENSEURQ_H

#include "Tenseur.h"


/** @defgroup Les_classes_tenseurs_virtuelles_ordre4
*
*     BUT:   Definir les tenseurs d'ordre 4 de differentes composantes.
*     Les classes sont virtuelles pures.
*     Elles se declinent en fonction de la dimension du probleme.
*     L'objectif principal est de surcharger les differentes operations
*     classiques.
*
* \author    Gérard Rio
* \version   1.0
* \date       2/5/2002
* \brief       Définition des classes virtuelles pures de type Tenseur d'ordre 4, en coordonnées avec différentes variances.
*
*/



class TenseurBBBB;   // def anticipee
class TenseurHHBB;   // pour l'utilisation dans les produits contractes
class TenseurBBHH;   //
         
/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 4 fois contravariantes
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurHHHH
{
    friend TenseurHHHH & operator * (double  r, const  TenseurHHHH & t)
       { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite
    friend TenseurHH& operator && ( const TenseurBB & F ,  const TenseurHHHH & T)
       { return T.Prod_gauche(F);}
 
  public :
    // DESTRUCTEUR :
    virtual ~TenseurHHHH() {};
    
   // METHODES PUBLIQUES :
//1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
//2)    virtuelles    
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurHHHH & operator + ( const TenseurHHHH &) const  = 0;
    virtual void operator += ( const TenseurHHHH &) = 0;
    virtual TenseurHHHH & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurHHHH & operator - ( const TenseurHHHH &) const  = 0;
    virtual void  operator -= ( const TenseurHHHH &) = 0;
    virtual TenseurHHHH & operator = ( const TenseurHHHH &) = 0;
    virtual TenseurHHHH & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurHHHH & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurHH& operator && ( const TenseurBB & )  const = 0 ;
    
    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurHHHH & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurHHHH & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurHHHH &) const  = 0;
    int operator != ( const TenseurHHHH & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurHHHH & (void)
//      {cout << " appel de la conversion de type TenseurHHHH\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

 //  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
  
    // fonction pour le poduit contracté à gauche
    virtual TenseurHH& Prod_gauche( const TenseurBB & F) const = 0;
   
 }; 
 /// @}  // end of group

 
 /** @defgroup Les_classes_Maillons_tenseurs_ordre4
 *
 *     BUT:    On gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsXXXX"
 *  qui stocke les pointeurs sur les tenseurs intermédiaire d'ordre 4
 *
 * \author    Gérard Rio
 * \version   1.0
 * \date       2/5/2002
 * \brief       Définition des classes qui stockent les pointeurs sur les tenseurs intermédiaire d'ordre 4.
 *
 */

 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsHHHH"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

 class PtTenseurHHHH;    // def de la liste chainee des tenseurs intermediaires
      
 /// @addtogroup Les_classes_Maillons_tenseurs_ordre4
 ///  @{

 /// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsHHHH 
 { public :
     ///liberation de la place occupee par des tenseurs crees pour les
     /// operations intermediaires
     static void Libere();
     /// enregistrement de l'ajout d'un tenseur
     static void NouveauMaillon(const TenseurHHHH *); // enregistrement de l'ajout d'un tenseur
     
     /// dernier maillon
     static PtTenseurHHHH * maille ;// dernier maillon
     #ifdef MISE_AU_POINT
       /// nombre de maillon courant sauvegarde
       static int nbmailHHHH;  // nombre de maillon courant sauvegarde
     #endif
 };
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 4 fois covariantes
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurBBBB
{ friend TenseurBBBB & operator * (double  r, const  TenseurBBBB & t) 
     { return ( t*r); } ;
  // produit contracte à gauche avec un tenseur d'ordre 2
  // différent de à droite
  friend TenseurBB& operator && ( const TenseurHH & F ,  const TenseurBBBB & T) 
     { return T.Prod_gauche(F);} 
 
  public :
   // DESTRUCTEUR :
    virtual ~TenseurBBBB() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurBBBB & operator + ( const TenseurBBBB &) const  = 0;
    virtual void operator += ( const TenseurBBBB &) = 0;
    virtual TenseurBBBB & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurBBBB & operator - ( const TenseurBBBB &) const  = 0;
    virtual void  operator -= ( const TenseurBBBB &) = 0;
    virtual TenseurBBBB & operator = ( const TenseurBBBB &) = 0;
    virtual TenseurBBBB & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurBBBB & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurBB& operator && ( const TenseurHH & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurBBBB & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurBBBB & B,bool plusZero) = 0;

    // test
    virtual int operator == ( const TenseurBBBB &) const  = 0;
    int operator != ( const TenseurBBBB & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
//        
//    // conversion de type
//    operator TenseurBBBB & (void)
//      {cout << " appel de la conversion de type TenseurBBBB\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
   // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
	
	   // fonction pour le poduit contracté à gauche
    virtual TenseurBB& Prod_gauche( const TenseurHH & F) const = 0;
 }; 
/// @}  // end of group

 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsBBBB"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurBBBB;    // def de la liste chainee des tenseurs intermediaires

/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsBBBB
 { public :
    ///liberation de la place occupee par des tenseurs crees pour les
    /// operations intermediaires
    static void Libere();
    /// enregistrement de l'ajout d'un tenseur
    static void NouveauMaillon(const TenseurBBBB *); // enregistrement de l'ajout d'un tenseur
    
    /// dernier maillon
    static PtTenseurBBBB * maille ;// dernier maillon
    #ifdef MISE_AU_POINT
      /// nombre de maillon courant sauvegarde
      static int nbmailBBBB;  // nombre de maillon courant sauvegarde
    #endif
 };
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes mixte HHBB
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurHHBB
{  friend TenseurHHBB & operator * (double  r, const  TenseurHHBB & t)
     { return ( t*r); } ;
   // produit contracte à gauche avec un tenseur d'ordre 2
   // différent de à droite
   friend TenseurBB & operator && ( const TenseurBB & F ,  const TenseurHHBB & T)
     { return T.Prod_gauche(F);} 
 
  public :
   // DESTRUCTEUR :
   virtual ~TenseurHHBB() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurHHBB & operator + ( const TenseurHHBB &) const  = 0;
    virtual void operator += ( const TenseurHHBB &) = 0;
    virtual TenseurHHBB & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurHHBB & operator - ( const TenseurHHBB &) const  = 0;
    virtual void  operator -= ( const TenseurHHBB &) = 0;
    virtual TenseurHHBB & operator = ( const TenseurHHBB &) = 0;
    virtual TenseurHHBB & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurHHBB & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurHH& operator && ( const TenseurHH & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurBBHH & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurHHBB & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurHHBB &) const  = 0;
    int operator != ( const TenseurHHBB & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurHHBB & (void)
//      {cout << " appel de la conversion de type TenseurHHBB\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurBB& Prod_gauche( const TenseurBB & F) const = 0;
 }; 
/// @}  // end of group

 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsHHBB"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurHHBB;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsHHBB
 { public :
    ///liberation de la place occupee par des tenseurs crees pour les
    /// operations intermediaires
    static void Libere();
    /// enregistrement de l'ajout d'un tenseur
    static void NouveauMaillon(const TenseurHHBB *); // enregistrement de l'ajout d'un tenseur
    
    /// dernier maillon
    static PtTenseurHHBB * maille ;// dernier maillon
    #ifdef MISE_AU_POINT
      /// nombre de maillon courant sauvegarde
      static int nbmailHHBB;  // nombre de maillon courant sauvegarde
    #endif
 };
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes mixte BBHH
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurBBHH
{   friend TenseurBBHH & operator * (double  r, const  TenseurBBHH & t)
     { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite
    friend TenseurHH & operator && ( const TenseurHH & F ,  const TenseurBBHH & T)
     { return T.Prod_gauche(F);} 
 
  public :
    // DESTRUCTEUR :
    virtual ~TenseurBBHH() {};
    
    // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurBBHH & operator + ( const TenseurBBHH &) const  = 0;
    virtual void operator += ( const TenseurBBHH &) = 0;
    virtual TenseurBBHH & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurBBHH & operator - ( const TenseurBBHH &) const  = 0;
    virtual void  operator -= ( const TenseurBBHH &) = 0;
    virtual TenseurBBHH & operator = ( const TenseurBBHH &) = 0;
    virtual TenseurBBHH & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurBBHH & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurBB& operator && ( const TenseurBB & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurHHBB & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurBBHH & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurBBHH &) const  = 0;
    int operator != ( const TenseurBBHH & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurBBHH & (void)
//      {cout << " appel de la conversion de type TenseurBBHH\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurHH& Prod_gauche( const TenseurHH & F) const = 0;
};
/// @}  // end of group
 
 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsBBHH"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurBBHH;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsBBHH
{ public :
    ///liberation de la place occupee par des tenseurs crees pour les
    /// operations intermediaires
    static void Libere();
    /// enregistrement de l'ajout d'un tenseur
    static void NouveauMaillon(const TenseurBBHH *); // enregistrement de l'ajout d'un tenseur
    
    /// dernier maillon
    static PtTenseurBBHH * maille ;// dernier maillon
    #ifdef MISE_AU_POINT
      /// nombre de maillon courant sauvegarde
      static int nbmailBBHH;  // nombre de maillon courant sauvegarde
    #endif
};
/// @}  // end of group

class TenseurBHBH;

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 2 fois mixtes HBHB
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurHBHB
{   friend TenseurHBHB & operator * (double  r, const  TenseurHBHB & t)
       { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite resultat(k,l)=F(i,j) T(j,i,k,l)
    friend TenseurHB & operator && ( const TenseurHB & F ,  const TenseurHBHB & T)
       { return T.Prod_gauche(F);}
 
  public :
    // DESTRUCTEUR :
    virtual ~TenseurHBHB() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurHBHB & operator + ( const TenseurHBHB &) const  = 0;
    virtual void operator += ( const TenseurHBHB &) = 0;
    virtual TenseurHBHB & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurHBHB & operator - ( const TenseurHBHB &) const  = 0;
    virtual void  operator -= ( const TenseurHBHB &) = 0;
    virtual TenseurHBHB & operator = ( const TenseurHBHB &) = 0;
    virtual TenseurHBHB & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurHBHB & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurHB& operator && ( const TenseurHB & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurBHBH & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurHBHB & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurHBHB &) const  = 0;
    int operator != ( const TenseurHBHB & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurHBHB & (void)
//      {cout << " appel de la conversion de type TenseurHBHB\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

    //  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurHB& Prod_gauche( const TenseurHB & F) const = 0;
};
/// @}  // end of group
 
 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsHBHB"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurHBHB;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsHBHB
{ public :
   ///liberation de la place occupee par des tenseurs crees pour les
   /// operations intermediaires
   static void Libere();
   /// enregistrement de l'ajout d'un tenseur
   static void NouveauMaillon(const TenseurHBHB *); // enregistrement de l'ajout d'un tenseur
   
   /// dernier maillon
   static PtTenseurHBHB * maille ;// dernier maillon
   #ifdef MISE_AU_POINT
     /// nombre de maillon courant sauvegarde
     static int nbmailHBHB;  // nombre de maillon courant sauvegarde
   #endif
};
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 2 fois mixtes BHBH
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurBHBH
{   friend TenseurBHBH & operator * (double  r, const  TenseurBHBH & t)
       { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite resultat(k,l)=F(i,j) T(j,i,k,l)
    friend TenseurBH & operator && ( const TenseurBH & F ,  const TenseurBHBH & T)
       { return T.Prod_gauche(F);}
 
  public :
   // DESTRUCTEUR :
    virtual ~TenseurBHBH() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurBHBH & operator + ( const TenseurBHBH &) const  = 0;
    virtual void operator += ( const TenseurBHBH &) = 0;
    virtual TenseurBHBH & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurBHBH & operator - ( const TenseurBHBH &) const  = 0;
    virtual void  operator -= ( const TenseurBHBH &) = 0;
    virtual TenseurBHBH & operator = ( const TenseurBHBH &) = 0;
    virtual TenseurBHBH & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurBHBH & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurBH& operator && ( const TenseurBH & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurHBHB & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurBHBH & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurBHBH &) const  = 0;
    int operator != ( const TenseurBHBH & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
   	virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurBHBH & (void)
//      {cout << " appel de la conversion de type TenseurBHBH\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurBH& Prod_gauche( const TenseurBH & F) const = 0;
  };
/// @}  // end of group
 
 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsBHBH"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurBHBH;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsBHBH
{ public :
   ///liberation de la place occupee par des tenseurs crees pour les
   /// operations intermediaires
   static void Libere();
   /// enregistrement de l'ajout d'un tenseur
   static void NouveauMaillon(const TenseurBHBH *); // enregistrement de l'ajout d'un tenseur
   
   /// dernier maillon
   static PtTenseurBHBH * maille ;// dernier maillon
   #ifdef MISE_AU_POINT
     /// nombre de maillon courant sauvegarde
     static int nbmailBHBH;  // nombre de maillon courant sauvegarde
   #endif
};
/// @}  // end of group

class TenseurBHHB;

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 2 fois mixtes HBBH
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurHBBH
{   friend TenseurHBBH & operator * (double  r, const  TenseurHBBH & t)
       { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite resultat(k,l)=F(i,j) T(j,i,k,l)
    friend TenseurBH & operator && ( const TenseurHB & F ,  const TenseurHBBH & T)
       { return T.Prod_gauche(F);}
 
  public :
   // DESTRUCTEUR :
    virtual ~TenseurHBBH() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurHBBH & operator + ( const TenseurHBBH &) const  = 0;
    virtual void operator += ( const TenseurHBBH &) = 0;
    virtual TenseurHBBH & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurHBBH & operator - ( const TenseurHBBH &) const  = 0;
    virtual void  operator -= ( const TenseurHBBH &) = 0;
    virtual TenseurHBBH & operator = ( const TenseurHBBH &) = 0;
    virtual TenseurHBBH & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurHBBH & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurHB& operator && ( const TenseurBH & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurBHHB & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurHBBH & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurHBBH &) const  = 0;
    int operator != ( const TenseurHBBH & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurHBBH & (void)
//      {cout << " appel de la conversion de type TenseurHBBH\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurBH& Prod_gauche( const TenseurHB & F) const = 0;
  };
/// @}  // end of group
 
 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsHBBH"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurHBBH;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsHBBH
{ public :
   ///liberation de la place occupee par des tenseurs crees pour les
   /// operations intermediaires
   static void Libere();
   /// enregistrement de l'ajout d'un tenseur
   static void NouveauMaillon(const TenseurHBBH *); // enregistrement de l'ajout d'un tenseur
   
   /// dernier maillon
   static PtTenseurHBBH * maille ;// dernier maillon
   #ifdef MISE_AU_POINT
     /// nombre de maillon courant sauvegarde
     static int nbmailHBBH;  // nombre de maillon courant sauvegarde
   #endif
};
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_virtuelles_ordre4
///  @{
//------------------------------------------------------------------
///          cas des composantes 2 fois mixtes BHHB
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       2/5/2002
class TenseurBHHB
{   friend TenseurBHHB & operator * (double  r, const  TenseurBHHB & t)
      { return ( t*r); } ;
    // produit contracte à gauche avec un tenseur d'ordre 2
    // différent de à droite resultat(k,l)=F(i,j) T(j,i,k,l)
    friend TenseurHB & operator && ( const TenseurBH & F ,  const TenseurBHHB & T)
      { return T.Prod_gauche(F);}
 
  public :
   // DESTRUCTEUR :
    virtual ~TenseurBHHB() {};
    
   // METHODES PUBLIQUES :
    //1)   non virtuelles
    int Dimension() const{ return dimension;}; // retourne la dimension du tenseur
    //2)    virtuelles
    // initialise toutes les composantes à val
    virtual void Inita(double val) = 0;   
    // operations 
    virtual TenseurBHHB & operator + ( const TenseurBHHB &) const  = 0;
    virtual void operator += ( const TenseurBHHB &) = 0;
    virtual TenseurBHHB & operator - () const  = 0;  // oppose du tenseur
    virtual TenseurBHHB & operator - ( const TenseurBHHB &) const  = 0;
    virtual void  operator -= ( const TenseurBHHB &) = 0;
    virtual TenseurBHHB & operator = ( const TenseurBHHB &) = 0;
    virtual TenseurBHHB & operator * (const double &) const  = 0  ;
    virtual void  operator *= ( const double &) = 0;
    virtual TenseurBHHB & operator / ( const double &) const  = 0;
    virtual void  operator /= ( const double &) = 0;
    
    // produit contracte à droite avec un tenseur du second ordre
    // (différent  de à gauche !!)
    virtual TenseurBH& operator && ( const TenseurHB & )  const = 0 ;

    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    // les 2 premiers indices sont échangés avec les deux derniers indices
    virtual TenseurHBBH & Transpose1et2avec3et4() const  = 0; 
    
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    virtual void Affectation_trans_dimension(const TenseurBHHB & B,bool plusZero) = 0;
 
    // test
    virtual int operator == ( const TenseurBHHB &) const  = 0;
    int operator != ( const TenseurBHHB & a)  const 
       { return !(*this == a);};
    
    // Retourne la composante i,j,k,l du tenseur
    // acces en  ecriture, 
 	  virtual void Change (int i, int j, int k, int l,const double& val) =0;
    // en cumul : équivalent de +=
    virtual void ChangePlus (int i, int j, int k, int l,const double& val) =0;

    // Retourne la composante i,j,k,l du tenseur
    // acces en lecture seule
	   virtual double  operator () (int i, int j, int k, int l) const =0;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    virtual double MaxiComposante() const = 0;
        
//    // conversion de type
//    operator TenseurBHHB & (void)
//      {cout << " appel de la conversion de type TenseurBHHB\n";
//       return *this;}; 
 
	   // lecture et écriture de données
    virtual istream & Lecture(istream & entree) = 0;
    virtual ostream & Ecriture(ostream & sort)  const = 0;

//  protected :
	
    // variables
    int dimension; // dimension du tenseur
    double * t;  // pointeur des données
       
  protected :
	
    // sortie d'un message standard
    // dim = dimension du tenseur argument
    void Message(int dim, string mes) const ;
    
    // fonction pour le poduit contracté à gauche
    virtual TenseurHB& Prod_gauche( const TenseurBH & F) const = 0;
  };
/// @}  // end of group
 
 // on gère les tenseurs intermédiaires au travers d'une classe  "LesMaillonsBHHB"
 // qui stocke les pointeurs sur les tenseurs intermédiaire

class PtTenseurBHHB;    // def de la liste chainee des tenseurs intermediaires
/// @addtogroup Les_classes_Maillons_tenseurs_ordre4
///  @{

/// def d'un maillon de liste chainee pour memoriser les differents tenseurs intermediaires
class LesMaillonsBHHB
{ public :
   ///liberation de la place occupee par des tenseurs crees pour les
   /// operations intermediaires
   static void Libere();
   /// enregistrement de l'ajout d'un tenseur
   static void NouveauMaillon(const TenseurBHHB *); // enregistrement de l'ajout d'un tenseur
   
   /// dernier maillon
   static PtTenseurBHHB * maille ;// dernier maillon
   #ifdef MISE_AU_POINT
     /// nombre de maillon courant sauvegarde
     static int nbmailBHHB;  // nombre de maillon courant sauvegarde
   #endif
};
/// @}  // end of group

//==============================================================================
/// Résolution du probleme de gestion de la definition de tenseurs supplementaires lors
/// d'ecriture de grandes expressions. Il est necessaire de liberer l'espace
/// apres les calculs
/// la fonction libereTenseur libere tout l'espace de tous les types de tenseurs
///==============================================================================

 void LibereTenseurQ() ;


#ifndef MISE_AU_POINT
  #include "TenseurQ.cc"
  #define  TenseurQ_H_deja_inclus
#endif
 
#endif  
