IPB

Bienvenue invité ( Connexion | Inscription )

> Un langage rare APL, supporté maintenant par l'éditeur ATOM
Options
Jaypee
posté 14 Dec 2020, 19:16
Message #1


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Le forum développeur en langages divers est plutôt calme et je me permets donc de faire un vagabondage avec un des langages "bizarres" que j'apprécie, le langage APL.
En effet, j'ai été récemment surpris que l'éditeur de programmation ATOM avait non seulement le support de la syntaxe APL mais que cela en faisait l'un des éditeurs APL les plus confortables que j'ai jamais pratiqué.
Peut-être que dans ces conditions, de nouveaux programmeurs curieux aimeraient s'y frotter un peu ?

APL est rare. Au temps des ordis 8-bit, seuls le Tandy TRS80 et une variété de Commodore, le super-PET 9000 de l'université canadienne de Waterloo en avaient une implémentation.
Rodnay Zacks, l'auteur de livre sur la programmation du 6502, avait créé la sienne, mais je ne l'ai jamais vue.
Avant cette époque, il équipait un IBM portable très rare, antérieur au PC DOS qu'on connait, l'IBM 5100 Modèle A, A comme APL.
Après cette époque, un portable ultra-rare à base de 68000, l'Ampère WS-1, n'a jamais trouvé son public, vendu seulement en France, hors de son Japon d'origine, jamais validé par la FCC aux USA,... Avis aux les collectionneurs.

APL est né chez IBM à la fin des années 1950, créé par Kenneth Iverson.
De nos jours, il existe soit une version OpenSource GNU APL, soit une version commerciale gratuite Dyalog APL, qui est devenue l'état de l'art du langage.
DyalogAPL propose aussi un portail très pratique en libre d'accès :
http://TryAPL.org
En France, le langage a été popularisé par Bernard Legrand http://www.afapl.asso.fr/AFAPL_2006_v2.pdf

Pourquoi s'y intéresser aujourd'hui ?
- Parce c'est un langage orienté calcul ou Data, avant le Big Data
- Parce qu'il manipule directement des tableaux, et qu'il a inspiré des langages comme R.
- Parce que l'environnement de développement est plus aisé d'approche que dans le passé, j'ai cité ATOM.

Commençons par un exemple simple :
Cette semaine, j'ai un peu marché et j'ai gardé le kilométrage journalier, et voici ma semaine :
Lundi : 5 km
Mardi : 3 km
Mercredi : 8 km
Jeudi : 2 km
Vendredi : 6 km
Samedi : 8 km
Dimanche : 10 km

Quelle a été ma moyenne ?
Code
  kms ← 5 3 8 2 6 8 10
  +/kms ÷ ⍴ kms
6

Essayez ça sur TryAPL.org
+/kms c'est une réduction par l'addition du vecteur kms, s'il avait fallu tout multiplier on aurait pu écrire ×/kms
⍴ kms c'est la dimension de kms, 7 éléments
Et la division n'est pas la barre utilisée pour la réduction, mais la superposition de : et -, qui donne le signe de division utilisé par les calculettes.

A propos de la réduction, les habitués de Big Data connaissent les moteurs de Map Reduce, on parle de la même reduction dans les deux cas.
Et si vous êtes plutôt Scala, il s'agit de l'opération «fold».

Maintenant, avec ces kilomètres vous pouvez préférer des totaux partiels après chaque jour. Facile, c'est l'opérateur de scan qui le fait.
Code
  +\kms
5 8 16 18 24 32 42

Le scan existe dans ReactJS ou dans Scala.

Comme vous le voyez, avec ces caractères spéciaux, il n'était pas facile d'avoir un environnement de dév, il fallait des claviers spéciaux,
des terminaux et des imprimantes spéciales. Plus aujourd'hui, les caractères APL sont dans l'UNICODE supporté par tous les ordis modernes.

Voyons un autre problème simple, mais très matheux, l'intersection d'une droite et d'un plan dans l'espace.
C'est l'un des exemples du portail Rosetta qui recense les résolutions de ce genre de problème dans différents langages. Mais pas en APL... du moins avant ce post.

Défi Rosetta : Intersection droite et plan

L'énoncé :
- Soit une droite dans l'espace 3D, définie par un point D et un vecteur directeur V
- Soit un plan dans l'espace 3D, défini par un point P et un vecteur normal N
- Trouver l'intersection I de la droite et du plan
- Données : D = (0, 0, 10), V = (0, -1, -1), P = (0, 0, 5), N = ( 0, 0, 1)

On va commencer par raisonner géométriquement avec les vecteurs:
Puisque le point I appartient à la droite, il existe un paramètre t ∊ R, tel que le vecteur DI = t×V
Le vecteur DI c'est en fait I - D de coordonnées Ix - Dx, etc on ne va pas aller par là, on va rester au niveau Point et Vecteur.
Donc on a I - D = t × V, ou encore I = D + t × V

Comme I appartient aussi au plan, tout vecteur du plan est normal à N.

Les maths nous disent si deux vecteurs sont normaux, leur produit scalaire est nul.
Le produit scalaire de A par B est le nombre AxBx + AyBy + AzBz, et il est noté A.B, et là encore on va rester à ce haut niveau, sans descendre aux x, y, z.
Les maths nous apprennent deux propriétés du produit scalaire qui vont nous être utiles:
- Il est distributif par rapport à l'addition de vecteurs : ( A + B ).C = A.C + B.C
- Il est associatif par rapport à la multiplication externe par un réel : (t × A).B = t × A.B

Réf: Patrice Wira : Un rappel sur les matrices

Ici, on veut exprimer que le vecteur IP est normal à N, et le vecteur IP c'est P - I, comme vu précédemment.

Donc on a (P - I).N = 0, remplaçons I par sa valeur D + t × V.
(P - D - t × V).N = 0
Utilisons la distributivité:
(P - D).N - (t × V).N = 0
Puis l'associativité:
(P - D).N - t × (V.N) = 0
D'où : t = (P - D).N ÷ V.N

Et l'APL dans tous ça ?
Le produit scalaire A.B se code +/A × B, donc on peut écrire :
t ← (+/(P - D) × N) ÷ +/V × N
Ce qui permet de résoudre I :
I ← D + t × V

A essayer sur TryAPL.org
Code
  V ← 0 ¯1 ¯1
  D ← 0 0 10
  N ← 0 0 1
  P ← 0 0 5
  t ← (+/(P - D) × N) ÷ +/V × N
  I ← D + t × V

Et ça donne
I
0 ¯5 5

A comparer avec les autres langages !
J-P
PS: Tant qu'à faire... j'ai ajouté l'exemple au portail Rosetta
Portail Rosetta

Ce message a été modifié par Jaypee - 17 Dec 2020, 08:16.
Go to the top of the page
 
+Quote Post
 
Start new topic
Réponse(s)
Jaypee
posté 5 Apr 2021, 14:39
Message #2


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Continuons cette série, avec deux exemples simples de manipulations des chaines de caractères qui sont traitées directement comme des vecteurs de caractères.

Comme tout vecteur, on a vu qu'on pouvait les indicer pour en extraire les valeurs choisies, et que le résultat a la même dimension que les indices, qui commencent à 1:
Code
      'A'[1 1 1]
AAA
         'NICHE'[3 4 2 5 1]
CHIEN


Premier petit défi, extraire les 4 premiers mots d'un texte.
Code
      t ← 'Un texte pour illustrer le code'

On trouve l'emplacement des espaces avec un masque booléen. Espace égal t, la comparaison va être distribuée ou mappée à chaque caractère de t.
Code
       ' ' = t
0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0

On a déjà vu le scan la barre oblique vers la gauche, qui fait des cumuls partiels. kms = kilomètres journaliers
Code
       kms ← 5 3 8 2 6 8 10
      + \ kms
5 8 16 18 24 32 42

On va l'appliquer au masque booléen pour compter le nombre d'espaces rencontrés :
Code
      + \ ' ' = t
0 0 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 5 5 5 5 5

On va superposer le texte et le masque juste pour mieux visualiser, c'est juste un truc en passant ça ne fait pas partie de la résolution du défi. On voit que le nombre augmente juste à la rencontre de l'espace avant chaque mot,
Code
       t,[0.5]+\' ' = t
U n   t e x t e   p o u r   i l l u s t r e r   l e   c o d e
0 0 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 5 5 5 5 5

Et pour ne retenir que 4 mots comme le défi le demande, il faut s'arrêter juste avant les 4. On va donc un fois de plus distribuer ou mapper la comparaison:
Code
      4 > +\ ' ' = t
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0

Ce masque booléen va servir pour sélectionner ou rejeter les caractères du texte original, et donc permet de résoudre ce défi, ce qui est fait avec l'opérateur barre oblique à droite /.
Code
       (4 > +\ ' ' = t) / t ← 'Un texte pour illustrer le code'
Un texte pour illustrer

Défi 1 relevé !

Maintenant, défi n°2, imaginons que nous sommes en train de construire une sorte de traitement de texte, et que pour avoir des colonnes de taille homogène de 40 colonnes, il faille élargir les espaces, rajouter du blanc au blanc.
On trouve facilement la taille du texte avec l'opérateur Rhô :
Code
      ⍴t
31

Il va donc falloir ajouter 9 espaces pour faire 40 caractères. Trouvons l'indice des espaces existants, grâce au même masque qui va sélectionner dans la liste des indices ceux en face des 1. On génère les indices de 1 à n avec l'opérateur iota. Et toujours l'astuce pour visualiser.
Code
      (' ' = t),[0.5]⍳⍴t
0 0 1 0 0 0 0 0 1  0  0  0  0  1  0  0  0  0  0  0  0  0  0  1  0  0  1  0  0  0  0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
      (' ' = t)/⍳⍴t
3 9 14 24 27

L'opérateur Rhô utilisé avec un argument à gauche, sert à "remplir" un vecteur. A gauche le nombre final, à droite le motif qui va âtre ré-utilisé autant de fois que nécessaire.
Code
      4 ⍴ 1 0
1 0 1 0

On va donc remplir un vecteur d'indices des espaces avec 9 valeurs, répétées si nécessaire:
Code
     (40 - ⍴t)⍴((' ' = t)/⍳⍴t)    
3 9 14 24 27 3 9 14 24

On va allonger la liste des indices originaux, avec ces indices supplémentaires, une simple virgule fait le collage de deux vecteurs. On va introduire la variable i pour le résultat:
Code
i ← (⍳⍴t),(40 - ⍴t)⍴(' ' = t)/⍳⍴t    
      i
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 3 9 14 24 27 3 9 14 24

L'idée est de trier le vecteur i aux valeurs croissantes. APL a un opérateur le triangle superposé à la barre verticale qui donne les indices qui reconstruisent l'ordre croissant. Il ne fait pas le tri, mais donne les clés du tri, donc il faut indicer le vecteur original pour le trier:
Code
      ⍋'CADB'
2 4 1 3
      'CADB'[⍋'CADB']
ABCD

Faisons le pour i.
Code
      i[⍋i]
1 2 3 3 3 4 5 6 7 8 9 9 9 10 11 12 13 14 14 14 15 16 17 18 19 20 21 22 23 24 24 24 25 26 27 27 28 29 30 31

Et finalement, on indexe le texte original avec ce vecteur d'indices enrichis de 9 espaces, là où il y en avait déjà un:
Code
      t[i[⍋i← (⍳⍴t),(40 - ⍴t)⍴(' ' = t)/⍳⍴t← 'Un texte pour illustrer le code']]
Un   texte   pour   illustrer   le  code
      t[i[⍋i]],[0.5]⍳40
U n       t e x t  e           p  o  u  r           i  l  l  u  s  t  r  e  r           l  e        c  o  d  e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
      (⍳40),[0.5]s[i[⍋i←(⍳⍴s),(40-⍴s)⍴(' '=s)/⍳⍴s←'et ça marche pour ce texte aussi']]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
e t       ç a         m  a  r  c  h  e        p  o  u  r        c  e        t  e  x  t  e        a  u  s  s  i
      t[i[⍋i←(⍳⍴t),(40-⍴t)⍴(' '=t)/⍳⍴t]],[0.5]s[i[⍋i←(⍳⍴s),(40-⍴s)⍴(' '=s)/⍳⍴s]]
Un   texte   pour   illustrer   le  code
et   ça   marche  pour  ce  texte  aussi

Défi n°2 résolu !

Une petite explication pour l'opérateur virgule :

Rappel: Un vecteur n'a qu'une seule dimension, sa longueur. On a vu ⍴t ne retourne que cette dimension.
Une matrice a deux dimensions le nombre de lignes et le nombre de colonnes.
Un nombre seul n'a pas de dimension du tout, c'est un «scalaire».

On a vu que la virgule servait à coller, deux vecteurs, on appelle cette opération une «caténation».
Lorsque qu'on spécifie la dimension qui augmente entre crochets, l'opération devient un laminage.

Par convention, lorsqu'on augmente le nombre de dimensions, passant de vecteur à matrice par exemple, on utilise ,[0.5]

Ce message a été modifié par Jaypee - 6 Apr 2021, 14:49.
Go to the top of the page
 
+Quote Post

Les messages de ce sujet


Reply to this topicStart new topic
3 utilisateur(s) sur ce sujet (3 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 18th July 2025 - 09:19