Bash : meuh ?


23 mai 2011

Comment se comprend la commande suivante ?

echo "hello world world hello world" | awk '{$1=$1}1' OFS=":"

Sachant qu'elle produit la sortie :

hello:world:world:hello:world

On l'aura compris, ce qui me dérange, c'est ce qui est entre accolades...

Bash : des choses que je ne savais pas...


19 mai 2011

On en découvre tous les jours sur Bash, surtout si on l'a appris en fonction de ses besoins et pas globalement.

Ainsi, on va rediriger la sortie d'un find vers une boucle while et utiliser des pseudos-classes :

#!/bin/bash
# This bash script will locate and replace spaces in the filenames
DIR="."
# Controlling a loop with bash read command by redirecting STDOUT as a STDIN to while loop
# find will not truncate filenames containing spaces
find $DIR -type f | while read file; do
    # using POSIX class [:space:] to find space in the filename
    if [[ "$file" = *[[:space:]]* ]]; then
        # substitute space with "_" character and consequently rename the file
        mv "$file" `echo $file | tr ' ' '_'`
    fi;
done

Le mot-clé select existe en Bash :

select word in "linux" "bash" "scripting" "tutorial" 
do
  echo "The word you have selected is: $word"
  break     # Break, otherwise endless loop
done

Les expensions ANSI-C :

# as a example we have used \n as a new line, \x40 is hex value for @
# and \56 is octal value for .
echo $'web: www.linuxconfig.org\nemail: web\x40linuxconfig\56org'

Les redirections...

X>&Y : redirige le flux de X vers le flux Y
X> : redirige le flux X (par défaut stdout ou 1) vers un fichier
On peut combiner les redirections précédentes, par exemple : > file 2>&1
Les deux indicateurs de redirections sont équivalents : >& et &>, tous les deux redirigent stdout et stderr vers un fichier
< : remplace stdin avec le contenu d'un fichier
<X : remplace le flux X avec le contenu d'un fichier

Si on utilise ces opérations de redirections avec la commande "exec" on exécute la redirection pour toute la durée du processus courant ou jusqu'à une modification de cette redirection et plus seulement dans le contexte d'une commande donnée. Donner des exemples.

# Link filedescriptor 10 with stdin
# stdin replaced with a file
Exemple : exec 10<&0; exec < Fichier
Son opposé (pour restaurer) : exec 0<&10 10<&-

On va utiliser 'exec < Fichier' pour pouvoir, par exemple, faire un 'while read Line' et énumérer toutes les lignes du fichier Fichier.

Question : est-ce que 'cat Fichier | command' est équivalent à 'command < Fichier' ?

Les expressions et leurs calculs
let Var=Expression : permet le calcul de Expression et le placement de son résultat dans Var
On peut "expandre" (calculer le résultat d'une expression) avec $((Expression)) ou $[ Expression ]
On peut écrire Base#Valeur pour déclarer la base dans laquelle s'exprime la valeur

La sémantique (en construction)


5 avril 2009

Liste des verbes

Pour reprendre (tous) les verbes de la langue française :

wget -q "http://conjf.cactus2000.de/index.fr.php?begin=a&end=zzzzz" -O - | grep '\[' | grep '<a' | php -r '$in=file_get_contents("php://stdin"); preg_match_all("/>([^<]+) \[.*\]<\/a/", $in, $Matches); foreach ($Matches[1] as $item) { echo "INSERT INTO Verbs (id, name) values (0, \"".$item."\");\n";}' | mysql --user root -p testverbs

Ã? suivre

Il faut envoyer des requêtes utilisant les produits précédent à un script qui interrogerait un site comme le conjugueur.com :

for item in `mysql --user root -p 'select name from Verbs;'`; do wget 'http://www.leconjugueur.com/php5/index.php?v=`echo $item | tr A-Z a-z`' | storeConjugue

Les fichiers MHTML décodés en Bash


16 mai 2008

Fichiers MHT sous Bash

J'ai été confronté à un fichier MHTML (d'extension .mht) et j'avais donc deux options pour consulter son contenu (32 fichiers...) : soit je faisais du copier-coller et du décodage (quoted-printable - RFC - et base64 - RFC) \"à la main\" et j'avais mon contenu en à peine 5 minutes, soit je faisais un script pour automatiser tout ça. Devinez ce que j'ai choisi...

�a me permet de parler d'une petite astuce de décodage de contenu en base64 que j'avais trouvé je ne sais plus trop où :

openssl base64 -d -in inputFile -out outputFile
openssl base64 -d < inputFile > outputFile

Pour faire court, à partir du fichier .mht, on le découpe (avec csplit), on traite les parties suivant qui sont encodées en base64 (fichiers binaires) ou quoted-printable (pour les autres pages web dans le cas d'un frameset). Et hop !

#!/bin/bash

#Explode a .mht archive into its original files.
#Syntax : explodemht MHTFile DestFolder

#Needed : php (pour le rawurldecode), openssl (pour le base64 decode) et "recode" pour le Quoted-Printable

[[ ${#} -lt 2 ]] && echo "Pas assez d'arguments : le fichier MHT et le dossier de destination" && exit 1;

MHTFile=${1}
[[ ! -f $MHTFile ]] && echo "Le fichier <$MHTFile> n'existe pas." && exit 2;

mainFolder=${2}
[[ ! -d $mainFolder ]] && mkdir "$mainFolder";

#Passe 0 : on fait le split du fichier .mht
SplitPrefix="mht_exploding_"
csplit -f $SplitPrefix "$MHTFile" /^\-\-\-\-\-\-=_NextPart/ {*} > /dev/null

#Première passe : on extrait tous les fichiers de l'archive MIME et on les décode correctement
echo "On crée les fichiers :"
j=0
NewNames=()
OriginalName=()
Encodings=()
for item in $SplitPrefix*; do
    FileName=`cat $item| grep -m 1 "Content-Location:" | awk '{print $2}' | sed 's/\r//g'`
    OriginalNames[$j]=$FileName
    FileName=`php -q -r 'echo (isset($_SERVER["argv"][1]) ? rawurldecode($_SERVER["argv"][1]) : "");' ${FileName}`
    FileName=`echo ${FileName} | sed 's/\\\/\//g'`
    FileName=`basename "${FileName}" | sed 's/\r//g'`
    Encoding=`cat $item| grep -m 1 "Content-Transfer-Encoding:" | sed 's/\r//g' | awk '{print $2}'`
    Encodings[$j]=$Encoding
    FirstEmptyLine=`cat $item | sed 's/\r//g' | grep -m 1 -n '^$' | awk 'BEGIN{FS=":"}{print $1}'`
    ((FirstEmptyLine++))
    if [[ ${#FileName} -ne 0 ]]; then
        echo "Fichier $j : ${FileName} - ($Encoding)"
        NewNames[$j]=${FileName}
        [[ ${Encoding} == "base64" ]] && sed -n $FirstEmptyLine',$p' $item | openssl base64 -d -out "$mainFolder/${FileName}";
        if [[ ${Encoding} == "quoted-printable" ]]; then
            sed -n $FirstEmptyLine',$p' $item | recode windows-1252/CRLF.. | recode /qp.. > $mainFolder/${FileName}

        fi
    fi
    ((j++))
done

#Deuxième passe : on fixe les liens HTML qui peuvent être invalides
i=0
while [[ $i -lt $j ]]; do
    if [[ ${Encodings[$i]} == "quoted-printable" ]]; then
        k=0
        echo "On traite les liens du fichier ${NewNames[$i]}."
        while [[ $k -lt $j ]]; do
            [[ ${#NewNames[$k]} == 0 ]] && ((k++)) && continue;
            OriginalName=`echo -n ${OriginalNames[$k]} | sed 's@\\\@\\\\@g;s@&@&amp;@g;s@%26@&amp;@g'`
            cat $mainFolder/${NewNames[$i]} | sed 's@'$OriginalName'@'${NewNames[$k]}'@g;s@'${OriginalNames[$k]}'@'${NewNames[$k]}'@g' > tempfile.tmp
            cp tempfile.tmp $mainFolder/${NewNames[$i]}
            ((k++))
        done
    fi
    ((i++))
done

#On nettoie
rm -f tempfile.tmp
rm -f $SplitPrefix*

En fait c'est énervant à écrire. Parce que je suis trop bête et que je n'ai pas trouvé d'équivalent à rawurldecode sous Bash. Parce que le code n'est pas beau. Du tout. Et parce que ça marche, rageant...

Il faut donc inclure un programme C qui implémente le rawurldecode et coder tout ça un peu plus proprement...

Librairie de Math


19 août 2007

Librairie de math

La librairie que je suis en train de concevoir pour exécuter, entre autres choses, des calculs sur des polynômes, des vecteurs et des matrices.

#include <stdarg.h>
#include <math.h>

using namespace std;

class   QiXMath : public std::exception
{
    public:
        QiXMath(char* msg)      { _whatMsg = msg; }
        virtual const char* what() const throw()    {   return _whatMsg;    }
    protected:
        char*   _whatMsg;
};


//Pour représenter des fractions, ce qui est très utile pour les polynôme quand on veut des calculs exacts.
//Note : pour simplifier des nombres décimaux qui ont des séquences répétitives voir http://en.wikipedia.org/wiki/QiFraction_(mathematics)
//TOCHECK : l'opérateur /(int) ne doit pas être nécéssaire puisque j'ai un constructeur qui a un int en entrée, pourquoi dois-je en avoir un ???
template <class T>
class   QiFraction
{
    public:
        //Faire un constructeur avec un seul paramètre : le numérateur.
        QiFraction(T n, T d)        {   _n = n; _d = d; }
        QiFraction(T n=0)       {   _n = n; _d = 1; }
        QiFraction(float n) {   _n = (T) n; _d = 1; }
        QiFraction(int n)   {   _n = (T) n; _d = 1; }
        void    dump()      const
        {
            if (_n == 0 || _d == 1)     cout << _n;
            else    {
                if (_n == _d)       cout << "1";
                else    cout << _n << "/" << _d;
            }
        }
        QiFraction<T>&  operator+=(const QiFraction<T>& a)
        {
            T   P = pgcd(_d, a._d);
            T   NewD = (_d * a._d) / P;
            _n = _n * (NewD / _d) + a._n * (NewD / a._d);
            _d = NewD;
            return *this;
        }
        QiFraction<T>&  operator-=(const QiFraction<T>& a)
        {
            T   P = pgcd(_d, a._d);
            T   NewD = (_d * a._d) / P;
            _n = _n * (NewD / _d) - a._n * (NewD / a._d);
            _d = NewD;
            return *this;
        }
        QiFraction<T>&  operator*=(const QiFraction<T>& a)
        {
            _n *= a._n;
            _d *= a._d;
            //On simplifie la fraction
            T   Common = pgcd(_n, _d);
            _n /= Common;
            _d /= Common;
            return *this;
        }
        QiFraction<T>&  operator/=(const QiFraction<T>& a)
        {
            _n *= a._d;
            _d *= a._n;
            //On simplifie la fraction
            T   Common = pgcd(_n, _d);
            _n /= Common;
            _d /= Common;
            return *this;
        }
        QiFraction<T>   operator+(const QiFraction<T>& a)       const
        {
            QiFraction  Result(_n, _d);
            return Result += a;
        }
        QiFraction<T>   operator-(const QiFraction<T>& a)       const
        {
            QiFraction  Result(_n, _d);
            return Result -= a;
        }
        QiFraction<T>   operator*(const QiFraction<T>& a)       const
        {
            QiFraction  Result(_n, _d);
            return Result *= a;
        }
        QiFraction<T>   operator/(const QiFraction<T>& a)       const
        {
            QiFraction  Result(_n, _d);
            return Result /= a;
        }
        QiFraction<T>   operator/(T a)      const
        {
            QiFraction<T>   Result(_n, _d);
            return Result /= QiFraction<T>(a);
        }
        QiFraction<T>   operator/(int a)        const
        {
            QiFraction<T>   Result(_n, _d);
            return Result /= QiFraction<T>(a);
        }
        bool    operator>=(float t) const       {   return (float)_n/(float)_d > t;     }
        bool    operator==(float t) const       {   return (float)_n/(float)_d == t;    }
        operator float()    const   {   return (float)_n/(float)_d; }
        QiFraction<T>&  inverse()
        {
            T   Tmp = _n;
            _n = _d;
            _d = _n;
            return *this;
        }
        T   pgcd(T u, T v/*, int verbose=false*/)
        {
            T   M = 1;
            if (u<0)        u = (T)0-u;
            if (v<0)        v = (T)0-v;
            while (u && v)      {
//      if (verbose)        printf("pgcd(%d, %d)\n", u, v);
                if (!(u&1) && !(v&1))       { M <<= 1; u>>=1, v>>=1; }
                else    if (!(u&1) && v&1)      u>>=1;
                else    if (u&1 && !(v&1))      v>>=1;
                else    {       //Les deux nombres sont impairs
                    if (u>v)    u=(u-v)>>1;
                    else        v=(v-u)>>1;
                }
            }
            return M * (u ? u : v);
        }
//Note : ppcm(a,b) = (a*b)/pgcd(a,b)

    T   _n, _d;     //Numérateur et dénominateur
};


//###TODO (25%) : Exceptions
//###TODO : cacher l'évaluation du degré d'un polynôme
//###TODO : faire la factorisation simple d'un polynôme
//###TODO : faire des opérateurs pour QiMatrix et QiPolynomial
//###TODO : faire des opérateurs pour QiVector
template <class T>
class   QiPolynomial
{
    public:
        QiPolynomial(int rank)
        {
            _comps = NULL;
            _init(rank);
        }
        ~QiPolynomial()
        {
            DELETEARRAY(_comps);
        }
        QiPolynomial(const QiPolynomial<T>& original)
        {
            if (this != &original)      {
                _init(original.rank());
                int i;
                for(i=0; i<=rank(); i++)        _comps[i] = original.get(i);
            }
        }
    protected:
        void    _init(int rank)
        {
            if (rank<0)     return;
            _rank = rank;
            _comps = new T[_rank+1];
        }
        void    _expand(int nbWantedSlots)
        {
            int NewSize = nbWantedSlots;
            _comps = new T[NewSize];
            if (!_comps)        throw new QiXMath("QiPolynomial::_expand : NotImplemented");
//          memcpy();
        }
    public:
        //
        void    null()
        {
            int i;
            for(i=0; i<=rank(); i++)        _comps[i] = 0.0f;
        }
        void    primitive()
        {
            int Degree = degree();
            if (rank() < Degree+1)      _expand(Degree+1);
            int i, MaxIndex = degree();
            for(i=MaxIndex; i>=0; i--)      _comps[i+1] = _comps[i]/(i+1);
            _comps[0] = 0.0f;
        }
        void    add(const QiPolynomial<T>& op)
        {
            int i;
            int MaxIndex = op.rank();
            if (rank() < MaxIndex)      MaxIndex = rank();
            for(i=0; i<=MaxIndex; i++)          set(i, get(i) + op.get(i));
        }
        QiPolynomial<T>&    operator *= (const QiPolynomial<T>& a)
        {
            multiply(a);
            return *this;
        }
        bool    multiply(const QiPolynomial<T>& op)
        {
            if (degree() + op.degree() > rank())        return false;
            QiPolynomial    Temp(degree() + op.degree());
            int MaxIt = op.degree(), i, j;
            int CurrentDegree = degree();
            Temp.null();
            for(i=0; i<=MaxIt; i++)     {
                for(j=0; j<=CurrentDegree; j++)     {
                    T   CurrentValue = Temp.get(i+j);
                    T   NewInc = op.get(i) * get(j);
                    Temp.set(i+j, CurrentValue + NewInc);
                }
            }
            set(Temp);
            return true;
        }
        void    multiply(T coeff)
        {
            int i;
            int MaxIndex = degree();
            for(i=0; i<=MaxIndex; i++)      set(i, get(i)*coeff);
        }
        QiPolynomial<T>&    operator /= (const T& a)
        {
            int i;
            int MaxIndex = degree();
            for(i=0; i<=MaxIndex; i++)      {
                set(i, get(i) / a);
            }
            return *this;
        }
        void    set(const QiPolynomial& src)
        {
            int i;
            null();
            int MaxIndex = rank();
            if (MaxIndex>src.rank())        MaxIndex = src.rank();
            for(i=0; i<=MaxIndex; i++)      set(i, src.get(i));
//          _rank = src.rank();
        }
        void    setRaw(int maxDegree, ...)
        {
            if (maxDegree > rank())     return;
            va_list args;
            va_start(args, maxDegree);
            int i, j;
            for(i=maxDegree; i>=0; i--)     {
                float   Value = (float) va_arg(args, double);
                _comps[i] = Value;
            }
            va_end(args);
        }
        //On remplace la variable x du polynôme par un autre polynôme (x par x+1 par exemple).
        //On substitue donc Q(x) à x dans P(x), ce qui donne P(Q(x)), un autre polynôme en x.
        //La méthode :
        void    substitute(const QiPolynomial& newVar)
        {
            QiPolynomial    Value(newVar.degree() + degree()), Total(newVar.degree() + degree());
            QiPolynomial    Param(newVar.degree() + degree());
            int i;
            Param.null();
            Param.set(0, 1.0f);
            for(i=0; i<=degree(); i++)      {
                Value.set(Param);
                Value.multiply(get(i));
                Total.add(Value);
                Param.multiply(newVar);
            }
            set(Total);
        }
        T   get(int index)  const
        {
            if (index<0 || index>rank()+1)      throw new QiXMath("QiPolynomial::get out of bound");
            return _comps[index];
        }
        void    set(int index, T value)
        {
            if (index<0 || index>rank()+1)      throw new QiXMath("QiPolynomial::set out of bound");
            _comps[index] = value;
        }
        float   evaluate(T x)   const
        {
            int MaxIndex = degree();
            float   Current = 1.0f, Total = 0.0f;
            int i;
            for(i=0; i<=MaxIndex; i++)      {
                Total += Current * _comps[i];
                Current *= x;
            }
            return Total;
        }
        int     degree()    const       //Renvoie le degré du polynôme courant : l'indice du premier coefficient non-nul en partant des puissances élevées.
        {
            int i = rank();
            while (get(i) == 0.0f && i>0)       i--;
            return i;
        }
        void    dump()  const
        {
            int i, Degree = degree();
            for(i=Degree; i>=0; i--)        {
                if (i<Degree && get(i)>=0.0f)       printf("+");
                printf("%.10f", (float) get(i));
                if (!i)     continue;
                if (i==1)   printf("X");
                if (i>1)    printf("X^%d", i);
            }
            printf("\n");
        }
        void    dumpObjects()   const
        {
            int i, Degree = degree();
            for(i=Degree; i>=0; i--)        {
                T   CurValue = get(i);
                if (i<Degree && CurValue>=0.0f)     printf("+");
                if (CurValue != 0.0f)       {
                    get(i).dump();
                    if (!i)     continue;
                    if (i==1)   printf("X");
                    if (i>1)    printf("X^%d", i);
                }
            }
            printf("\n");
        }
        int     rank()  const   {   return _rank;   }
    protected:
        T*      _comps;
        int     _rank;
};

template <class T>
class   QiVector
{
    public:
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        class   ExQiVector : public std::exception
        {
            public:
                ExQiVector(char*)       {   }
        };
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        QiVector(int rank)      {   _comps = new T[rank];   _rank = rank;}
        ~QiVector()     {   DELETEARRAY(_comps) }
        void    null()  {
            int i;
            for(i=0; i<rank(); i++)     _comps[i] = 0.0f;
        }
        //On crée un vecteur de base
        void    base(int index)
        {
            if (index<0 || index>=rank())       return;
            null();
            set(index, 1.0f);
        }
        //###TODO : faire des exceptions pour les out of bounds.
        bool    set(int index, const T& value)  {
            if (index<0 || index >= rank())     return false;
            _comps[index] = value;
            return true;
        }
        bool    set(QiVector<T>& newValue)
        {
            if (rank() != newValue.rank())      return false;
            int i;
            for(i=0; i<rank(); i++)     _comps[i] = newValue.get(i);
            return true;
        }
        bool    add(int index, const T& value)
        {
            if (index<0 || index>=rank())       return false;
            return set(index, get(index) + value);
        }
        T   get(int index)      const
        {
            return _comps[index];
        }
        QiVector<T>& operator=(const QiVector<T>& original)
        {
            //###TODO : si les rangs sont différents on doit changer le rang de l'objet courant
            if (this != &original && rank() == original.rank())     {
                int i;
                for(i=0; i<rank(); i++)     _comps[i] = original.get(i);
            }
            return *this;
        }
        int     rank()  const   {   return _rank;   }
        void    dump()  const
        {
            int i;
            printf("(");
            for(i=0; i<rank(); i++)     {
                if(i)   printf(", ");
                printf("%f", _comps[i]);
            }
            printf(")\n");
        }
        void    dumpObjects()   const
        {
            int i;
            printf("(");
            for(i=0; i<rank(); i++)     {
                if(i)   printf(", ");
                _comps[i].dump();
            }
            printf(")\n");
        }
    protected:
        T*  _comps;
        int _rank;
};

//Matrice carrée constituée de vecteurs QiVector
template <class T>
class   QiMatrix
{
    public:
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        class   ExQiMatrix : public std::exception
        {
            public:
                ExQiMatrix(char*)       {   }
        };
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        QiMatrix(int rank)      {   _init(rank);    }
    protected:
        bool _init(int rank)
        {
            _comps = new QiVector<T>*[rank];
            int i;
            for(i=0; i<rank; i++)       _comps[i] = new QiVector<T>(rank);
            _rank = rank;
            return true;
        }
        bool _release()
        {
            int i;
            for(i=0; i<rank(); i++)         {
                DELETESINGLE(_comps[i]);
            }
            DELETEARRAY(_comps);
        }
        void    _count()    const
        {
            _nbUps = 0, _nbLows = 0, _nbDiags = 0;
            int i, j;
            for(i=0; i<rank(); i++)     {
                for(j=0; j<rank(); j++)     {
                    float   Value = get(i, j);
                    if (i>j && Value)       _nbLows++;
                    if (i<j && Value)       _nbUps++;
                    if (i==j && Value)      _nbDiags++;
                }
            }
            //
            _nbItemsInHalf = _rank*(_rank-1)/2 + _rank;
        }
    public:
        ~QiMatrix()     {   _release(); }

        void    null()      {   int i;  for(i=0; i<rank(); i++)     _comps[i]->null();  }
        void identity()
        {
            null();
            int i;
            for(i=0; i<rank(); i++)     _comps[i]->set(i, 1.0f);
        }
        T   get(int i, int j)       const
        {
            if (i<0 || j<0)     return 0.0f;
            if (i>=rank() || j>=rank())     return 0.0f;
            return _comps[i]->get(j);
        }
        QiVector<T>& get(int index) const
        {
            if (index<0 || index>=rank())       return *_comps[0];
            return *_comps[index];
        }
        bool    set(int i, int j, T value)
        {
            if (j<0 || j>=rank())   return false;
            _comps[i]->set(j, value);
            return true;
        }
        bool    setRaw(int setRank, ...)        {
            if (setRank != rank())  return false;
            va_list args;
            va_start(args, setRank);
            int i, j;
            for(i=0; i<rank(); i++)     {
                for(j=0; j<rank(); j++)     {
                    if (!_comps[i]->set(j, (float) va_arg(args, double)))       {
                        va_end(args);
                        return false;
                    }
                }
            }
            va_end(args);
            return true;
        }
        bool    setRow(int index, QiVector<T>& row)
        {
            if (rank() != row.rank())       return false;
            _comps[index]->set(row);
            return true;
        }
        //Multiplication matrice-matrice inplace
        QiMatrix<T>&    operator *= (const QiMatrix<T>& op)
        {
            multiply(op);
            return *this;
        }
        bool    multiply(const QiMatrix<T>& op)
        {
            if (rank() != op.rank())        return false;
            QiVector<T> Temp(rank());
            int i, j, k;
            for(i=0; i<rank(); i++)     {
                for(Temp.null(), j=0; j<rank(); j++)        {
                    for(k=0; k<rank(); k++)     {
                        Temp.add(j, get(i, k) * op.get(k, j));
                    }
                }
                setRow(i, Temp);
            }
            return true;
        }
        //
        QiVector<T> operator * (const QiVector<T>& op)      const
        {
            QiVector<T>     Result(op.rank());
            multiply(op, Result);
            return Result;
        }
        void    multiply(const QiVector<T>& op, QiVector<T>& result)    const
        {
            int i, j;
            for(i=0; i<rank(); i++)     {
                T   Total = 0.0f;
                for(j=0; j<rank(); j++)     {
                    Total += get(i, j) * op.get(j);
                }
                result.set(i, Total);
            }
        }
        //Copy constructor
        QiMatrix(const QiMatrix<T>& original)
        {
            _init(original.rank());
            int i;
            for(i=0; i<rank(); i++)     *_comps[i] = original.get(i);
        }
        bool    isLower()   const
        {
            _count();
            return _nbLows + _nbDiags == _nbItemsInHalf;
        }
        bool    isDiagonal()    const
        {
            _count();
            return _nbDiags == rank();
        }
        //Inverse la matrice courante "inplace"
        void    inverse()
        {
            if (isLower())      {
                //Cas pour les matrices triangulaires inférieures
                QiVector<T> Temp(rank());
                int i, j, k;
                T   Total;
                for(i=0; i<rank(); i++)     {
                    Temp.null();
                    for(j=0; j<=i; j++)     {
                        Total = 0.0f;
                        for(k=j; k<i; k++)      {
                            T   NormalIK = get(i, k);
                            T   InvKJ = get(k, j);
                            Total += NormalIK * InvKJ;
                        }
                        T   DeltaIJ = i == j ? 1.0f : 0.0f;
                        T   MainCoeff = get(i, i);
                        T   InverseCoeff = (DeltaIJ - Total) / MainCoeff;
                        Temp.set(j, InverseCoeff);
                    }
                    setRow(i, Temp);
                }
            }   else    if(isDiagonal())        {
                int i;
                for(i=0; i<rank(); i++)     set(i, i, 1.0f/get(i, i));
            }   else    throw new QiXMath("QiMatrix::inverse : not yet implemented.");
        }

        void    dump()  const
        {
            int i;
            for(i=0; i<rank(); i++)     _comps[i]->dump();
        }
        void    dumpObjects()   const
        {
            int i;
            for(i=0; i<rank(); i++)     _comps[i]->dumpObjects();
        }
        int     rank()  const   {   return _rank;   }
        //
        bool    isUpper()   const;
        bool    isInversible()  const;
    protected:
        QiVector<T>**   _comps;
        int _rank;
        //
        mutable     int _nbUps, _nbLows, _nbDiags, _nbItemsInHalf;
};

Bien se souvenir qu'ici je cherche plus à être exact que rapide, c'est sûr que pour un moteur 3D j'utiliserai les classes QiMatrix et QiVector avec beaucoup de pincettes !!!

Accueil1 2 3