mercredi 20 mai 2015

shebang postgresql

Le shebang (#!) est un en-tête de fichier qui indique au système d'exploitation que ce fichier est en fait un script. Le chemin d'accès vers l'interpréteur à utiliser est indiqué juste après sur la même ligne.
Ainsi un script bash devrait avoir une première ligne du genre:

#!/bin/bash

Problème avec les scripts interprétés par psql:  pour SQL, # n'indique pas un commentaire, mais bien  --
Faisons le test dans un terminal psql:


Nous imprimons (\p) ce qui sera envoyé au serveur pour exécution avant de procéder (;). Nous constatons que le commentaire a disparu et n'est pas envoyé au serveur.
Par contre:



'# commentaire' figure bien dans ce qui est envoyé au serveur, d'où l'erreur.

Nous avons le même genre d'erreur lors de l'exécution du script sbpsql1x:

#!/usr/bin/psql -f
select now()
\echo 'Sera envoyé au serveur:'
\echo
\p
\echo
\echo 'Procédons:'
\echo
;

Vérifions:


Comme proposé ici on peut remplacer la ligne shebang par

--() { :; }; exec psql [options] -f "$0"

Notre script devient sbpsql2x:

--() { :; }; exec psql bdtest -f "$0" 
select now()
\echo 'Sera envoyé au serveur:'
\echo
\p
\echo
\echo 'Procédons:'
\echo
;

Cette fois ça fonctionne car la ligne 1 est traitée comme un commentaire par psql:


Cette ligne n'est pas vraiment un shebang (où est #! ?). Elle commence par la définition d'une fonction (notée --) associée à une commande qui ne fait rien (:). Comme la fonction n'est jamais utilisée on pourrait mettre n'importe quoi (par exemple echo 'Hello') à la place de :).
En toute rigueur on devrait commencer le script par un véritable shebang, comme ceci:

#!/bin/bash
--() { :; }; exec psql bdtest -f "$0" 
select now()
...

Mais on retombe alors sur la même erreur.

Une autre possibilité est celle utilisée dans ce script (sbpsql3x):

#!/bin/sh
exec sh -c "tail -n +3 $0 | psql bdtest -f -" 
select now()
\echo 'Sera envoyé au serveur:'
\echo
\p
\echo
\echo 'Procédons:'
\echo
;

La commande tail envoie à partir de la ligne 3 le contenu du script (dont le nom se trouve dans $0) vers la commande psql. L'option -f - signifie que psql lit les instructions depuis l'entrée standard qui dans notre cas est la sortie standard de tail (voir ici: les canaux de communication avant et après un pipe: stdout de la commande en aval est connecté à stdin de la commande en amont).



samedi 16 mai 2015

script psql

Nous avons déjà rencontré dans ce blog des scripts appelant la commande psql.
Mais cette fois nous allons partir des notions de base et entrer dans plus de détails.
psql est une commande permettant de se connecter à une base de données PostgreSQL.
Ainsi la commande

psql bdtest

ouvre un terminal interactif connecté à la base de données bdtest:


Bien sûr pour que cette commande simplifiée fonctionne il faut notamment qu'il existe un utilisateur PostgreSQL appelé toto et que le serveur PosgreSQL se trouve sur la même machine que le client.
Au début le seul utilisateur PostgreSQL existant est postgres.
Pour démarrer il faut d'abord devenir postgres et créer l'utilisateur PostgreSQL toto en lui donnant le privilège de créer des bases de données:


Etant redevenu toto après exit, il nous est alors loisible de créer bdtest avec la commande createdb.

Bref, tout cela est très loin: bdtest existe depuis longtemps et contient maintenant de multiples données qui ont déjà été présentées et utilisées dans le cadre de ce blog, notamment les tables utilisations et dépenses créées par ces instructions:

CREATE TABLE utilisations
(code_u CHAR(2) PRIMARY KEY,
 signification VARCHAR(20))
;
CREATE TABLE dépenses
(référence CHAR(9) PRIMARY KEY,
 date_exec DATE,
 montant NUMERIC(13,2),
 détails VARCHAR(50),
 code_u CHAR(2) REFERENCES utilisations)
;


Précisons encore que si nous ne sommes pas (plus) toto, il nous est possible de se connecter en tant que toto avec la commande

psql bdtest toto

(Si les fichiers pg_hba.conf et pg_ident.conf ont été correctement configurés)
Dans le terminal interactif nous pouvons exécuter des commandes ou entrer des instructions SQL telles que:

SELECT *
FROM dépenses
WHERE détails = 'Docteur Lebon'
;

Si cette instruction se trouve déjà dans un fichier (par exemple lebon.sql), il n'est nul besoin de la retaper. Il suffit de lancer la commande:

\i lebon.sql

(lebon.sql doit se trouver là où on est, c'est-à-dire dans ~/SQL/bdtest)

Si nous redirigeons l'entrée standard vers le fichier lebon.sql:

psql bdtest < lebon.sql

nous n'ouvrons pas alors de terminal interactif. L'instruction est exécutée, puis la liaison vers bdtest est coupée:



Autre possibilité:

psql bdtest <<FIN

redirige l'entré standard vers le document qui se trouve ici (here-document), donc vers ce qui sera tapé à l'écran (jusqu'au mot FIN):



Le système attend la saisie suivante.
Après envoi du mot FIN, le résultat s'affiche:


Mais quel est l'avantage de cette procédure par rapport au terminal interactif, puisqu'il faut quand même saisir l'instruction SQL?
L'avantage est que cette procédure peut être utilisée dans un script:le here-document est alors dans le script lui-même.
Soit le script lebonx:

#!/bin/bash
echo
psql bdtest <<FIN
SELECT *
FROM dépenses
WHERE détails = 'Docteur Lebon'
FIN

que nous avons rendu exécutable (et qui se trouve dans ~/SQL/bdtest).
Exécutons le:



Nous pouvons passer en paramètre la valeur du détail demandé, comme dans le script détailx:

#!/bin/bash
echo $1
echo
psql bdtest -v détails="$1" <<FIN
SELECT *
FROM dépenses
WHERE détails = :'détails'
FIN

L'option -v dans la commande crée la variable psql détails avec la valeur $1.
Procédons:


Nous aimerions maintenant un script qui établisse le relevé des dépenses pour une certaine catégorie. Nous ignorons le code lié à cette catégorie: donc on veut passer en clair le nom de cette catégorie: par exemple 'Santé' pour les dépenses de santé et non '01'.
Considérons le script dépensex:

#!/bin/bash
psql bdtest  -q \
-v signification="$1" <<FIN
\pset numericlocale
\pset border 2
\pset linestyle u
\pset footer
\pset title 'Dépenses $1 \n'
\echo
SELECT code_u
FROM utilisations
WHERE signification = :'signification'
\gset
SELECT référence, date_exec::text as date, détails, montant
FROM dépenses
WHERE code_u = :'code_u'
UNION
SELECT 'TOTAL', '', '', sum(montant)
FROM dépenses
WHERE code_u = :'code_u'
order by 1
FIN

Nous avons expliqué ici comment utiliser la commande \gset
Testons le script:


L'option -q permet d'éliminer les différents messages informatifs résultant des commandes \pset:

Title is "Dépenses Grande surface".
Showing locale-adjusted numeric output.
Border style is 2.
Line style is unicode.

Si le détail passé en paramètre n'existe pas, d'autres messages polluent l'output:

no rows returned for \gset
ERROR:  syntax error at or near ":"
LINE 3: WHERE code_u = :'code_u'
                       ^
Ces messages transitent par le canal des erreurs (canal 2). Pour les éliminer nous ajoutons les instructions suivantes au début script:

exec 6>&2
exec 2>/dev/null

Tout d'abord nous sauvegardons les caractéristiques du canal 2 dans le canal 6, ensuite nous redirigeons le canal 2 vers le néant c'est-à-dire /dev/null.
(Nous avons déjà parlé des redirections ici )

En fin de script nous avons:

 exec 2>&6 6>&-

(A partir du canal 6, remise du canal 2 dans son état initial; fermeture du canal 6)

D'autre part nous voudrions nous servir de awk pour séparer la ligne 'TOTAL' des autres. Pour ce faire nous envoyons l'output de psql dans un fichier temporaire (créé par mktemp) qui sert d'output à awk (\o | awk ... est inopérant dans ce contexte).
Le script définitif est donc:

#!/bin/bash
fichier=$(mktemp)
exec 6>&2
exec 2>/dev/null
psql bdtest toto -q \
-v signification="$1" <<FIN
\pset numericlocale
\pset border 2
\pset linestyle u
\pset footer
\pset title 'Dépenses $1 \n'
\echo
\o $fichier
SELECT code_u
FROM utilisations
WHERE signification = :'signification'
\gset
SELECT référence, date_exec::text as date, détails, montant
FROM dépenses
WHERE code_u = :'code_u'
UNION
SELECT 'TOTAL', '', '', sum(montant)
FROM dépenses
WHERE code_u = :'code_u'
order by 1
FIN
exec 2>&6 6>&-
awk 'NR==5 {y=$0};/TOTAL/ {print y};1' $fichier

awk sauvegarde la ligne 5 (instruction 1) pour l'imprimer si la ligne lue contient 'TOTAL' (instruction 2), ensuite toutes les lignes lues sont imprimées puisque la condition 1 est toujours vraie (instruction 3)

Testons:


Si le libellé n'existe pas ('grande surface'), il n'y a aucun output (les messages d'erreurs ont disparus).
Peut-être on préférerait avoir ceci:


Dans ce cas il suffit d'ajouter dans le here-document (avant le premier SELECT) la meta-commande

\set code_u

ce qui initialise la variable code_u. De ce fait l'instruction SQL qui vient après \gset ne se plante plus. 

Certains pourraient dire que les scripts présentés ici ne sont pas des scripts psql mais des scripts bash qui appellent la commande psql.
Certes, mais l'emploi de la ligne shebang

#!/usr/bin/psql bdtest -f 

conduit invariablement à une erreur.
Nous avons trouvé ici un shebang qui fonctionne pour psql:

--() { :; }; exec psql -f "$0"

Ainsi le script détailpx

--() { :; }; exec psql bdtest -v détails="$1" -f "$0"
\echo :détails
\echo
SELECT *
FROM dépenses
WHERE détails = :'détails'

donne le même résultat que le script détailx présenté plus haut.

Cependant dès l'instant où la commande psql est terminée, nous quittons le script. Il est impossible de faire transiter dans le même script l'output du SELECT par awk comme auparavant.

Si nous partons du script dépensepx:

--() { :; }; exec psql bdtest -q -v signification="$1" -f "$0"
\pset numericlocale
\pset border 2
\pset linestyle u
\pset footer
\set titre 'Dépenses ':signification
\pset title :titre'\n'
\set code_u
\echo
SELECT code_u
FROM utilisations
WHERE signification = :'signification'
\gset
SELECT référence, date_exec::text as date, détails, montant
FROM dépenses
WHERE code_u = :'code_u'
UNION
SELECT 'TOTAL', '', '', sum(montant)
FROM dépenses
WHERE code_u = :'code_u'
order by 1

et que nous voulons apporter les mêmes améliorations que pour le script dépensex, nous devons l'appeler à partir du script bash dépense0x

#!/bin/bash
fichier=$(mktemp)
exec 7>&1
exec 1>$fichier
exec 6>&2
exec 2>/dev/null
./dépensepx "$1"
exec 1>&7 7>&-
awk 'NR==6 {y=$0};/TOTAL/ {print y};1' $fichier
exec 2>&6 6>&-

Comme auparavant nous redirigeons la sortie des erreurs (canal 2) vers le néant.
De plus nous redirigeons la sortie standard (canal 1) vers le fichier temporaire créé, de sorte que toute la sortie du script dépensepx s'effectuera vers ce fichier. Bien sûr, il faut revenir à la situation initiale avant l'exécution de awk pour que l'output de ce dernier soit dirigé vers l'écran. Remarquons que awk sauvegarde la ligne 6 au lieu de la 5 comme auparavant.
Explication:
La commande \o $fichier utilisée dans le script dépensex envoie dans $fichier le résultat des instructions SQL.
En cas de redirection de la sortie standard, c'est la totalité de l'output qui part vers $fichier, donc aussi la ligne générée par \echo.


dimanche 26 avril 2015

Mise à jour table PostgreSQL

Sur une machine de bureau (appelée rigel), où est installé un serveur PostgreSQL, nous disposons d'une base de données bdtest.
La même base de données existe sur un ordinateur portable (aldebaran).
Au cours d'un voyage, des rangées ont été ajoutées à une table (nommée dépenses) sur l'ordinateur portable.
Il s'agit maintenant, travaillant depuis l'ordinateur portable, de mettre à jour la table dépenses sur l'ordinateur fixe.
Nous allons procéder simplement sans utilisation d'outils de synchronisation.
Evaluons tout d'abord la situation au niveau de l'ordinateur de bureau:

toto@aldebaran:~/SQL/bdtest$ psql bdtest -h rigel -t <<FIN
> SELECT max(référence)
> FROM dépenses
> FIN
Password: 
 2013-0023

2013-0023 n'est pas le mot de passe (celui-ci bien que tapé n’apparaît pas) mais bien le résultat du query.
Copions dans un fichier dépenses les rangées supplémentaires existant sur aldebaran:

toto@aldebaran:~/SQL/bdtest$ psql bdtest <<FIN
> \copy (SELECT * FROM dépenses \
> WHERE référence > '2013-0023') \
> TO dépenses
> FIN

Pour finir, connectons nous de nouveau à rigel pour copier les nouvelles rangées et vérifions ensuite que la mise à jour a bien été effectuée:

toto@aldebaran:~/SQL/bdtest$ psql bdtest -h rigel -t <<FIN
> \copy dépenses FROM dépenses
> SELECT max(référence)
> FROM dépenses
> FIN
Password: 
 2014-0019

En image:


jeudi 23 avril 2015

Meta-commande gset

Dans l'article Variables dans psql nous avons regretté le fait que l'instruction

SELECT ..
INTO ..

utilisée dans un terminal psql, serve à créer une nouvelle table et non à initialiser une variable.
En effet nous aurions aimé pouvoir exécuter quelque chose comme

SELECT code_u
INTO :code
FROM utilisations
WHERE signification = 'Santé';

et ensuite

SELECT *
FROM dépenses
WHERE code_u = :'code';

Mais cela ne fonctionne pas.

Une façon simple de contourner le problème consiste à envoyer l'instruction

SELECT code_u
FROM utilisations
WHERE signification = 'Santé'

vers le serveur avec la méta-commande gset et non avec un point-virgule.
La requête ne doit retourner qu'une rangée et chaque colonne de cette rangée sera stockée dans une variable portant le nom de la colonne.
Testons:



Il nous est loisible de donner à la variable un nom différent de celui prévu par défaut en modifiant l'instruction envoyée comme ceci:

SELECT code_u AS code
FROM utilisations
WHERE signification = 'Santé'

Testons:





Signalons que la deuxième instruction pourrait aussi s'écrire de la sorte:



Rappelons une autre solution présentée dans un billet précédent.
Il s'agit de créer une fonction avec

CREATE FUNCTION fdépenses(text)
RETURNS SETOF dépenses
AS $$
DECLARE
code dépenses.code_u%TYPE;
usage alias for $1;
BEGIN
SELECT code_u
INTO code
FROM utilisations
WHERE signification = usage;
RETURN QUERY SELECT *
FROM dépenses a WHERE code_u =  code  ORDER BY référence;        
END;
$$ LANGUAGE 'plpgsql';

dont l'utilisation conduit au même résultat:


dimanche 22 mars 2015

spin-orbite

Dans cet article nous allons donner des exemples d'utilisation de geogebra.
Geogebra est un outil qui permet des réalisations assez bluffantes : constructions géométriques, graphiques de fonctions, dérivées, intégrales, maxima etc.
Nous avons voulu  explorer un terrain, moins flamboyant, plus aride, à savoir celui du calcul matriciel.
Travaillant sous ubuntu 14.04 nous avons ajouté le dépôt geogebra aux sources de logiciel (voir ici) afin de pouvoir installer le paquet geogebra5 qui fournit une version de geogebra  avec la fenêtre de calcul formel.
Plutôt que de traiter d'un problème purement mathématique, nous avons préféré aborder un cas concret issu de la physique quantique. Il s'agit d'un cas relativement ardu que nous avons essayé de simplifier au maximum. Tout une série de développements théoriques seront passés sous silence. Cependant, bien que le but déclaré soit de montrer des exemples d'utilisation de geogebra, nous n'hésiterons pas à donner la signification physique des propriétés mathématiques rencontrées : de la sorte même le non initié pourra goûter à la beauté de cette théorie.

Considérons un électron (dans un atome) possédant un moment cinétique orbital l = 1.  Aie ! Tout de suite des mots qui fâchent : moment cinétique orbital. Mais il n'est pas nécessaire de comprendre ce qu'il en est exactement pour la suite du raisonnement. L'important est de savoir qu'une mesure de ce moment suivant un certain axe (z), une mesure d'une grandeur qui sera notée lz , ne peut donner que 3 résultats : +1, 0, -1 (dans un système d'unités adapté) . C'est extraordinaire puisqu'une grandeur physique varie normalement de manière continue. Mais il s'agit ici de physique quantique. A ces 3 valeurs correspondent 3 états notés |1>, |0>, |‑1>.  Ces 3 états sont des états particuliers de l'ensemble des états du moment cinétique, ensemble qui est appelé l'espace des états. Cet ensemble jouit de propriétés telles qu'il s'agit d'un espace vectoriel. Les éléments de cet espace, les états,  peuvent certes s'appeler vecteurs, mais ceux-ci n'ont rien à voir avec les vecteurs tels qu'on les conçoit communément (flèches). A la grandeur physique lz correspond un opérateur lz agissant dans cet espace. L'action de lz sur les états |1>, |0>, |‑1> est donnée par

lz |m> = m |m> (m = 1, 0, -1)

Le vecteur état est multiplié par la valeur de  lz  dans l'état.
On dit que les états |m> sont des états propres de lz avec la valeur propre m.
Toute combinaison linéaire a |1> + b |0> + c |‑1> défini un autre état. Les 3 états (normalisés)  |1>, |0>, |‑1> constitue une base de l'espace des états considéré qui est donc un espace à 3 dimensions.  Dans cette base un état quelconque est représenté par une matrice colonne :


Les opérateurs sont représentés par des matrices carrées 3X3. Faire agir un opérateur sur un état revient à multiplier la matrice colonne état par la matrice de l'opérateur, ce qui redonne une matrice colonne.
Dans une base constituée de vecteurs propres d'un opérateur, la matrice qui le représente est diagonale et les éléments diagonaux sont les valeurs propres.
Aux grandeurs physiques lx, ly , mesures du moment cinétique suivant les axes  x, y (qui constituent avec l'axe z le référentiel) correspondent, tout comme pour lz, des opérateurs lx, ly qui agissent dans l'espace des états. 
Les opérateurs lz, lx, ly sont représentés par les matrices:

Pour la matrice de lz le résultat est évident au vu de ce qui précède. Pour les 2 autres matrices, il faudra admettre le résultat vu que nous faisons l'impasse sur de nombreux développement théoriques. Pour ly précisons que i représente l'unité imaginaire qui s'obtient dans geogebra avec ALT +  i .

Les valeurs possibles pour lz sont les valeurs propres de la matrice correspondante. Il en est de même pour les autres grandeurs : les valeurs permises sont toujours les valeurs propres des matrices qui les décrivent.
Recherchons dans geogebra (fenêtre de calcul formel), les valeurs propres de l
Nous encodons 
l_x := 1/sqrt(2) {{0,1,0},{1,0,1},{0,1,0}}
pour la matrice de l
et 
Déterminant(l_x - λ Identité(3))

pour l''équation aux valeurs propres:


En ligne 2, geogebra a calculé le déterminant encodé et établi de manière formelle l'équation aux valeurs propres. Il nous reste à résoudre cette équation du second degré. Il suffit de sélectionner la ligne 2 et ensuite utiliser l'outil 'Résoudre' :


La ligne 2 est modifiée et y figurent maintenant les valeurs propres de lx qui sont identiques à celles de lz :


Rien que de plus normal : il n'y a aucune raison pour que les résultats d'une mesure suivant x soient différents des résultats d'une mesure suivant z. Les états (vecteurs) propres de lx sont des combinaisons linéaires particulières de |1>, |0>, |‑1>. Si lx est bien déterminé, lz ne l'est plus. Un état quelconque n'est sans doute état propre d'aucun des trois opérateurs lz, lx, ly . Il n'en est pas de même en ce qui concerne l'opérateur
l2 = lx2 + ly2 + ly2
En effet, on peut constater à l'aide de geogebra que l'espace des états tout entier est un espace propre de l'opérateur l2 avec la valeur propre l (l+1) = 2 :


Ce qui signifie que n'importe quel état a |1> + b |0> + c |‑1> (représenté par une matrice colonne) est état propre de l2 avec la valeur propre 2 :


Dans notre espace à 3 dimensions l² est donc parfaitement déterminé et vaut toujours l (l + 1) = 2.

Introduisons le spin de l'électron.  Il s'agit d'un autre moment cinétique qui (dans le modèle planétaire de l'atome) correspond à la rotation de l’électron sur lui-même. Celui-ci projeté sur un axe peut prendre les deux valeurs ±½ , ce qui multiplie par deux les possibilités. L'espace à 3 dimensions présenté plus haut devient un espace à 6 dimensions sous-tendu par les états (vecteurs) :
|1 +>, |1 ‑>, |0 +>, |0 ‑>, |‑1 +>, |-1 ‑> . 
états propres communs à lz et sz, opérateur lié à sz, mesure du spin suivant l'axe z:


lz |m±> = m |m±> (m = 1, 0, -1)
             sz |m±> = ±½ |m±>                           

Les matrices de  lz, lx, ly se transforment en matrices 6X6 par explosion de chacun de leurs éléments en 1 matrice 2X2 suivant le schéma :
Elles deviennent donc:

Les 3 opérateurs sz, sx, sy  correspondant aux composantes du spin sont dans notre espace à 6 dimensions (et avec la base choisie) représentés par les matrices :

Le long de la diagonale de ces matrices nous reconnaissons, reproduites chaque fois en 3 exemplaires les matrices 2x2 liées au spin telles qu'on les rencontre dans la littérature (scientifique).
Après avoir encodé toutes ces matrices 6x6 dans geogebra nous pouvons vérifier que notre espace des états à 6 dimensions reste espace propre de (avec la même valeur propre que précédemment)


et qu'il est espace propre de avec la valeur propre s (s+1) = 3/4 (s = 1/2) :


Maintenant nous allons passer à un niveau supérieur et aborder la composition du moment cinétique. Cependant nous allons nous efforcer de rendre la suite compréhensible même pour les non initiés.
Introduisons le moment cinétique total :

j = l + s

ce qui implique :
jz = lz + sz 

La matrice de jz s'obtient aisément à partir des matrices de lz et de sz:


La matrice est diagonale : tous les vecteurs base sont vecteurs propres de j.
De plus les sous-espaces ε1 (sous-tendu par |1 ‑> et |0 +>) et є2 (sous-tendu par  |0 ‑> et |‑1 +>) sont des espaces propres.
Les vecteurs de base sont-ils vecteurs propres de ?
Non, hélas !
Certes ils sont tous vecteurs propres de l² + s² avec la valeur propre 2 + 3/4 = 11/4 puisque comme nous venons de le voir l'espace des états est espace propre deet .
Malheureusement:
j² = l² + s² + 2 l.s

Construire la matrice de 2 l.s demande de fastidieux calculs. Avec geogebra, c'est plus simple: taper une seule ligne suffit :



La matrice n'est pas diagonale.
Cependant les vecteurs 1 et 6 de la base (|1 +> et |-1 ->) sont vecteurs propres de 2 l.s de valeur propre 1 et donc de avec la valeur propre j (j+1) = 11/4 + 1 = 15/4, soit j = 3/2 .
Comme ils sont aussi vecteurs propres de jz (valeur propre +3/2 et -3/2), nous les noterons |3/2 ±3/2> et pouvons écrire:


Pour le reste, les sous-espaces ε1 et ε2  sont globalement invariants (stables) sous l'action de l.s :
Le transformé par l.s d'un état de ε1 (ou ε2) est encore un état du même sous-espace.
De plus nous savons que ε1 et ε2 sont des espaces propres de jz. Donc les vecteurs propres de l.s (et donc de) présents dans ε1 et ε2 sont des vecteurs propres communs à et jz.
Procédons avec geogebra à la recherche des valeurs propres de 2 l.s dans ε1 :


Utilisons l'outil 'Résoudre'  après sélection de la ligne 2:
La ligne 2 est modifiée et y figurent maintenant les solutions de l'équation :


Nous retrouvons la valeur propre 1 déjà rencontrée.
Rappelons que si λ = 1 la valeur propre de est j (j + 1) = 2 + 3/4 + 1 = 15/4, soit j = l + 1/2 = 3/2.
Si λ = -2 la valeur propre de est j (j + 1) = 2 +3/4 -2 = 3/4, soit j = l – 1/2 = 1/2.

Recherchons le vecteur propre de valeur propre 1. Soient a et b les composantes de ce vecteur. En image les différentes étapes du calcul :


En ligne 3 nous écrivons que l'action de A sur le vecteur le laisse inchangé.
En ligne 4 nous indiquons la condition pour que cela se réalise.
En ligne 5 se trouve la condition de normalisation (nous supposons a et b réels)
Après avoir sélectionné les lignes 4 et 5, nous appliquons l'outil 'Résoudre', ce qui engendre la ligne 6 où figurent 2 solutions. Nous retenons la solution avec a positif. Notons ce vecteur |3/2 3/2> car j = 3/2 et ce vecteur appartient à ε1 qui est espace propre de jz avec la valeur propre 1/2.
Intéressons-nous maintenant au vecteur propre de valeur propre -2. Les étapes sont les mêmes que précédemment :


Cette fois j =1/2 comme expliqué précédemment et donc notre vecteur sera noté  |1/2 1/2>.
Suite aux résultats obtenus avec geogebra nous pouvons donc écrire:

Procédant de même dans ε2  nous obtenons cette fois :

Les coefficients qui apparaissent dans les relations ci-dessus ne sont rien d'autres que des coefficients de Clebsch-Gordan.

mardi 27 janvier 2015

Fonction bilan

A la fin du billet Variables dans psql, nous avions montré comment impacter le résultat d'instructions SQL (contenues dans un fichier) par initialisation d'une variable.
Ainsi

bdtest=> \set an 2013 
bdtest=> \i bilan.sql

donnera en ouput le bilan de 2013 pour autant que les instructions SQL de bilan.sql contiennent des clauses WHERE du genre:

WHERE an = :'an'

Nous pouvons aussi créer un fichier bilanx contenant la commande

psql bdtest -v an=$1 -f bilan.sql

L'année du bilan sera de la sorte transmise en paramètre au programme.
Il faut rendre bilanx exécutable:

toto@aldebaran:~/SQL/bdtest$ chmod +x bilanx

avant de pouvoir l'utiliser:



bilan.sql qui contient l'ensemble des instructions SQL se trouve sur le poste client (où est exécuté bilanx).
Nous voudrions ne pas avoir besoin de fichier contenant les instructions SQL et que celles-ci se trouvent sur le serveur.
Pour ce faire il nous faut créer une fonction (PL/pgsql). Si nous voulons retourner le même genre de bilan que dans le billet Sous-totaux dans terminal psql, cette fonction sera par exemple créée par:

DROP function fbilan (integer);
CREATE FUNCTION fbilan (integer)
RETURNS TABLE (mois text, "sous-total" text, ref char(9), datexec text, cred numeric(13, 2), deb numeric(13, 2), solde numeric(13,2), usage char(5))
AS $$
DECLARE
année alias for $1;
BEGIN
RETURN QUERY  
SELECT (A.mois_n ||' ' || A.mois), ' ', reference,
date_exec::text, crédit, débit,
  (SELECT SUM(B.solde)
  FROM opérationsv B
  WHERE B.reference <= A.reference
  AND B.an = A.an
  AND B.mois_n = A.mois_n),
  contrepartie
FROM opérationsv A
WHERE an::numeric = année
UNION
SELECT (C.mois_n ||' ' || C.mois), 'SOUS-TOTAL', '', '',
SUM(crédit), SUM(débit), SUM(C.solde),
'' 
FROM opérationsv C
WHERE an::numeric = année
GROUP BY C.mois_n, C.mois
UNION
SELECT 'TOTAL', '', '', '',
SUM(crédit), SUM(débit), SUM(D.solde),
''
FROM opérationsv D
WHERE an::numeric = année
ORDER by 1, 2 , 3;
END;
$$ LANGUAGE 'plpgsql';

Un problème se pose: la commande

psql bdtest -v an=$1 -c 'select * from fbilan(:an)'

conduit à une erreur:


alors que ceci:



fonctionne et donne le résultat escompté après un appui sur ENTER.

L'instruction  SQL constitue ce qui est appelé un here-document. Quelques éléments concernant cette notion se trouve dans le billet Les secrets de cat.

En conséquence, créons le fichier fbilax:

psql bdtest -v an=$1 -P numericlocale -P footer \
-P border=2 -P linestyle=u \
-P title='Bilan '$1 <<FIN
SELECT * 
FROM fbilan(:an)

FIN

Nous le rendons exécutable, puis nous le testons:


Ça fonctionne, mais si nous voulons améliorer l'output nous avons intérêt à utiliser awk.
Pour ce faire, créons le fichier fbilanx:

fichier=$(mktemp)
psql bdtest -v an=$1 -P numericlocale -P footer \
-P border=2 -P linestyle=u \
-P title='Bilan '$1 -o $fichier <<FIN
SELECT * FROM fbilan(:an); 
FIN
echo
awk 'NR==4 {y=$0};/SOUS-TOTAL/ {print y;print;print y};!/SOUS-TOTAL/' $fichier

dont l'utilisation après qu'il ait été rendu exécutable, nous fournit le résultat souhaité:


Grâce à l'option -o nous écrivons l'output de psql dans un fichier temporaire (créé par mktemp). Ce fichier temporaire sert d'input à awk. La ligne 4 (qui vient après le nom des colonnes) est alors mise en mémoire (première instruction awk) en vue d'une impression avant et après les lignes contenant le mot 'SOUS-TOTAL'. Pour les autres lignes, l'action par défaut (print) est exécutée. Le billet awk (introduction) contient tout ce qui est nécessaire pour la compréhension de ce qui précède.

Notons que si on est déjà dans un terminal psql, il n'est nul besoin de sortir pour procéder: