Bonjour,
Je souhaiterais vous présenter un projet que j'ai commencé il y a peu.
On pourrait dire qu'il ne s'agit d'une simple calculatrice en ligne de commande : ça ne serait pas faux en soit, juste incomplet.
En effet, il s'agit d'un interpréteur extrêmement simple (la classe "State", moins de 900 lignes de code pour le moment, header inclus) qui permet de gérer des opérations entre des symboles. Il est, dans sa conception, relativement générique et permet l'ajout de nouveaux types sans modifier le code de base de l’interpréteur.
Ainsi, il est muni par défaut de trois types fondamentaux :
- "Symbol" : la classe de base dont doit hériter tout type. Utilisée seule, cette classe ne sert à rien pour le moment, mis à part à déclarer des symboles sans les définir.
- "Scalar" : contient un nombre réel (double précision), muni des opérateurs mathématiques habituels : multiplication (*), division (/), addition (+) et soustraction (-).
- "Reference" : contient une chaine de caractère qui est évaluée à chaque fois que la référence apparait dans une expression. C'est en gros un raccourcis vers une expression plus compliquée.
Le support du type "Scalar" par défaut pourrait être retiré, l'interpréteur n'en dépendant pas explicitement (mais une calculette sans nombre, je trouve ça quand même dommage).
Pour montrer que l'ajout de nouveaux types est possible simplement, j'ai mis également à disposition un type supplémentaire : Vector.
Ressemblant beaucoup au std::vector du C++, le type Vector est un conteneur unidimensionnel homogène (il contient N valeurs de types identiques). Il n'y a strictement aucune restriction sur le type de valeur contenue, ainsi il est possible de créer des Vector de Vector, et toute autre combinaison qui vous passe par la tête.
Il possède deux opérateurs généraux : l'addition (+) et la soustraction (-), plus la multiplication par un "Scalar" (commutative). Les 3-Vectors (vectors à 3 composantes) disposent également, pour le fun, du produit vectoriel (^).
Enfin, on peut utiliser l'opérateur '[]' pour accéder aux composantes du vector, en utilisant soit la notation "canonique" vector[]index, soit la notation C++ vector[index].
La syntaxe de construction d'un vector est la suivante : <elt1, elt2, ...> (l'utilisation des parenthèses étant réservée à leur sens mathématique premier, qui permet de grouper les expressions).
L'interpréteur peut fonctionner soit en ligne de commande, soit en lisant les commandes directement à partir d'un fichier.
Voici donc une suite d'exemples d'utilisation commentés, qui valent mieux qu'on long discours.
Vous trouverez les binaires pour Windows, ainsi que les sources (tout à fait portables), à la fin du message.
On commence par créer deux symboles 'a' et 'b' en une seule commande. Le symbole ';' permet, comme en C++, de signaler à l'interpréteur la fin d'une instruction.
Le type Symbol est assez peu utile, on ne peut faire aucune opération dessus :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 > a;b Defining Symbol : a Defining Symbol : b
On peut en revanche, même si l'intérêt est limité, créer un vecteur à partir de ces deux symboles :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 > a*b Error : No match for operator 'Symbol * Symbol' in : a * b
Attention cependant, l'interpréteur est tatillon, et ne supporte pas qu'un symbole soit non déclaré :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 > v = <a,b> Defining Vector : v = <a, b>
On va maintenant passer aux nombres. Pour recommencer une nouvelle session sans fermer le programme, on peut utiliser la commande '~'. Utilisée seule, elle supprime tous les symboles précédemment définis, et utilisée devant le nom d'un symbole, elle détruit celui-ci.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 > w = <a,b,c> Error : Unknown symbol 'c'
Pour vérifier que tout s'est bien passé, on peut demander à l'interpréteur d'afficher le contenu de la variable 'a' :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 > ~v Vector 'v' erased > ~ Warning : This command will erase all symbols. Are you sure ? ([y|Enter]/n) y All symbols erased
Tout est ok ! On peut alors commencer sereinement. On affecte d'abord quelques valeurs numériques :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 > ?a 'a' is undefined
Puis on peut évaluer une expression compliquée :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 > a=1; b=2 Defining Scalar : a = 1 Defining Scalar : b = 2
Il est possible de rappeler le dernier résultat avec la commande '_' :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 > (9+7)*(3-a)/(10-(4-b)) Scalar : 4
On peut également mélanger joyeusement scalaires et vecteurs, ou manipuler les composantes (l'indice dans les crochet est cyclique : pour un vecteur de taille N, v[N+i] = v[i] et v[-i] = v[N-i]). En cas d’ambiguïté d'ordre d'opérateurs (comme pour la 2nde ligne), l'expression est lue de gauche à droite séquentiellement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 > _*_ Scalar : 16 > _*_ Scalar : 256
Pour compléter ce tour d'horizon, il ne nous reste plus qu'à présenter l'usage des références :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 > v = (0.5*_/b)*<1, 2*a, 3*b-2*a> Defining Vector : v = <64, 128, 256> > v[4]/v[-1]/v[0] Scalar : 0.0078125
Les références étant évaluées seulement lorsqu'on en fait usage, il est autorisé d'y faire figurer des symboles non définis. Elles ne pourront alors être complètement évaluées que lorsque tous les symboles qu'elles contiennent sont définis :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 > r &= b*c Defining Reference : r = b*c
Cette dernière ligne montre ce qu'il me reste à implémenter pour que le système de référence soit plus ou moins complet. L'expression '4*r' devrait retourner une nouvelle référence...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 > r Reference : b*c > c = <1,2,3> Defining Vector : c = <1, 2, 3> > r Vector : <2, 4, 6> > ~c Vector 'c' erased > r Reference : b*c > 4*r No match for operator 'Scalar * Reference' in : 4 * b*c
Si vous avez envie de crier à l'arnaque, vous en avez le droit : pour le moment, pas de calcul formel au menu... Mais c'est bien entendu sur la ToDo list !
Le but principal de ce programme n'est pas de concurrencer Mathematica/Mapple/etc, mais de proposer une solution gratuite, open source et légère permettant de faire de l'algèbre linéaire de base (pas de matrices pour le moment, mais rien ne m'en empêche) et du calcul tensoriel formel (et accessoirement, numérique).
Comme vous pouvez le voir sur mon profil, je suis étudiant en physique (Master 2 actuellement), et il m'arrive bien souvent d'avoir à calculer des expressions tensorielles relativement pénibles, dont j'aimerais vérifier le résultat rapidement par ordinateur. C'est de là qu'est partie l'envie de programmer ce petit bout de programme (plus ma passion un peu malsaine de ré-inventage de roue).
Voici donc comme promis les binaires :
Note : L'édition des messages anciens de plus de 3 jours est désactivée sur Developpez. Il est donc presque certain que les versions ci-dessous ne soient pas les plus récentes. Merci de visiter cette page pour être sûr d'avoir la dernière version : [click].
- Windows XP (32bit) v001 : [7z] (100Ko), [zip] (155Ko) (01h00, 24/09/2011)
- Ubuntu 11.10 (32bit) v001 : pas tout de suite !
... et les sources :
Le tout sous licence GNU GPL.
Pour compiler, vous devrez d'abord compiler la bibliothèque "Utils" qui se trouve dans le sous dossier du même nom. Elle n'a aucune dépendance ni configuration, et est donc très facile à compiler (les projets Code::Block sont fournis et prêts à l'emploi, d'ailleurs). La documentation Doxygen de cette bibliothèque est fournie ici : [7z] (262 Ko), [zip] (1329 Ko).
Partager