ajouts dossier Processus, Calculabilité, Recherche textuelle. Avec images et exercices.
293
Calculabilité/README.md
Normal file
@@ -0,0 +1,293 @@
|
||||
## Calculabilité et décidabilité en informatique ##
|
||||
|
||||
> A chaque problème sa non solution !
|
||||
|
||||
|
||||
|
||||
<img src="assets/bo.png" alt="bo" style="zoom:50%;" />
|
||||
|
||||
## Logique
|
||||
|
||||
#### Introduction à la décidabilité
|
||||
|
||||
Il vous est deja arrivé de prendre des décisions en suivant une logique. Dans la vie vous suivez la votre, en prenant des conseils, ou de par ce que vous avez appris à l'école. C'est donc quelque chose général.
|
||||
|
||||
Cela vous semble simple de définir la logique, mais en réalité, mise en pratique, cela devient plus complexe à commenter :
|
||||
mathématiquement, la logique n'a pas grand chose à voir avec celle dont on use au quotidien.
|
||||
|
||||
En informatique, une chose primordiale est l'utilisation et la mise au point d'algorithme, et donc de prise de décision.
|
||||
Ces décisions sont prises par le programme informatique via un shcéma de pensée que l'on peut représenter comme ceci :
|
||||
|
||||
<img src="assets/diagramme.png" alt="Diagramme" style="zoom:50%;" />
|
||||
|
||||
D'un point de vue mathématique ou informatique, ces paramètres et prises de décision sont de type booléen, (vrai ou faux)
|
||||
|
||||
On peut par exemple prendre des problèmes assez élémentaires :
|
||||
|
||||
|
||||
- X est il un nombre pair ?
|
||||
- Y est il une puissance de 3 ?
|
||||
- Dans un graphe, quel est le chemin le plus court passant par tous les sommets ?
|
||||
|
||||
Dans notre premier cas, nous avons en **instance de départ :** un entier naturel, qui, après être traité via le **paramètre** choisi (Si reste = 0 après une division par 2, alors nombre est pair) dans **l'algorithme**, ressortira en une réponse simple : *Oui* ou *Non* selon la **décision** prise.
|
||||
|
||||
### Définition
|
||||
|
||||
En informatique ou mathématiques, on peut parler d'une **fonction algorithmique**. Quand le résultat de celle ci, c'est à dire ce qu'elle *renvoit*, est un boléen, on parle de ***prédicat***
|
||||
|
||||
Un ***prédicat*** est une fonction qui ne prendra que des valeurs booléennes:
|
||||
|
||||
<p>
|
||||
|
||||
La réponse à un problème de décision est donc soit un booléen ou alors une valeur qui permet de répondre à un prédicat
|
||||
|
||||
|
||||
Exemple : Dans un graphe, connaitre le nombre de sommets permet de répondre à la question : le chemin que j'ai choisi est il le plus court passant par tous les sommets de ce graphe ?
|
||||
|
||||
Question dont la réponse est bel et bien un prédicat.
|
||||
|
||||
### Définition
|
||||
|
||||
Si, pour réponse à un problème, on peut en écrire un algorithme permettant la prise de décision et donc amenant à la résolution du dit problème, on parlera de problème ***décidable*** ou de <u>**décidabilité**</u>
|
||||
|
||||
Et donc, par extension, si un problème n'est pas soluble, on utilisera le terme ***Indécidabilité***
|
||||
|
||||
-------
|
||||
|
||||
## ~~La calcul habilité~~ La calculabilité
|
||||
|
||||
En informatique, plus précisemment dans la branche dite de programmation, nous utilisons un langage qui nous est propre afin de mettre en place nos idées dans un algorithme.
|
||||
|
||||
### Vocabulaire
|
||||
|
||||
Cela ne signifie pas pour autant que cet algorithme fonctionne : pour cela il faut vérifier que la propriété qu'on appelle ***Terminaison*** est bien respectée, et que l'algorithme nous mène bien à la réponse souhaitée.
|
||||
|
||||
On parlera également d'algorithme de ***haut niveau***: l'algorithme doit pouvoir être traduit en n'importe quel langage de programmation, il ne doit donc pas faire appel à des notions techniques relatives à un programme particulier ou bien à un système d'exploitation donné.
|
||||
|
||||
|
||||
Quel rapport avec la calculabilité ? Et bien une fonction mathématique, que l'on peut retranscrire sous forme d'algorithme afin de la programmer dans un langage informatique utilisé, est dite ***Calculable***
|
||||
|
||||
### Un peu d'histoire
|
||||
|
||||
En 1943, un mathématicien américain, du nom d'Alonzo Church définit une thèse dite "thèse de Church" qui affirme la notion de calculabilité : Tout traitement d'un système réalisable par un processus quel qu'il soit, peut être exprimé par un ensemble de règles de calcul.
|
||||
|
||||
Cet ensemble est défini lui même par les règles de calcul dont on prouve mathématiquement l'équivalence.
|
||||
|
||||
Cette thèse propose les règles suivante en matière d'algorithme :
|
||||
|
||||
1. L'algorithme consiste en un ensemble fini d'instructions simples et précises
|
||||
qui sont décrites avec un nombre limité de symboles.
|
||||
2. L'algorithme doit toujours produire le résultat en un nombre fini d'étapes.
|
||||
3. L'algorithme peut être suivi par un humain avec seulement du papier et un crayon.
|
||||
4. L'exécution de l'algorithme ne requiert pas d'intelligence de l'humain
|
||||
sauf celle qui est nécessaire pour comprendre et exécuter les instructions.
|
||||
|
||||
|
||||
### Trop long, j'ai pas lu !
|
||||
|
||||
Pour résumer : une fonction mathématique qui fonctionne selon un modèle existant fonctionnera dans n'importe quel modèle.
|
||||
|
||||
|
||||
|
||||
Si vous décidez de programmer une fonction qui vous dit si un nombre est pair en python, votre fonction devrait fonctionner dans un autre langage, pourvu que vous utilisiez les "codes" de ce langage.
|
||||
|
||||
Ici, en NSI, nous utilisons le langage Python, mais nous pourrions parfaitement transposer nos codes en C++, Java ou autre.
|
||||
|
||||
### Et la calculabilité dans tout ça ?
|
||||
|
||||
|
||||
Revenons au prédicat : si une fonction renvoie un prédicat, et que celui là est dit calculable, alors la prise de décision est possible. Une fonction calculable permet donc l'emergence de décisions décidables.
|
||||
|
||||
Ce qui signifie qu'il existe un algorithme permettant la résolution de cette fonction, ou d'un problème ammené par la fonction, et si un algorithme existe, alors nous sommes en mesure de programmer la fonction dans n'importe quel langage.
|
||||
|
||||
--------
|
||||
|
||||
## La décidabilité
|
||||
|
||||
### Vocabulaire
|
||||
|
||||
Une propriété est dite décidable si l'on peut déterminer son résultat (vrai ou faux) en un nombre fini d'étapes
|
||||
|
||||
C'est le principe même d'un algorithme, ou d'une recette de cuisine par exemple : on indique un nombre d'étapes qui doit mener, à terme, à un résultat.
|
||||
|
||||
Pour un problème, c'est la même chose : si l'on peut écrire un programme qui renvoit un prédicat permettant de calculer la réponse au problème de départ, alors on parlera de ***problème décidable***.
|
||||
|
||||
### Pourquoi est ce important ?
|
||||
|
||||
Imaginez, si votre programme, logiciel ou jeu vidéo favori rencontrait un problème d'execution et tournait en boucle quand vous l'utilisez. <br> Frustrant n'est ce pas ? Une personne qui souhaite développer des programmes doit s'assurer de la décidabilité de son travail.
|
||||
|
||||
### Et maintenant, des exemples !
|
||||
|
||||
Exercice : Prouver qu'un nombre est pair :
|
||||
|
||||
Nous allons définir une fonction \\(f : N --> {Vrai, Faux} \\) telle que f(n) est vraie si et seulement si \\(n\\)%2 == 0
|
||||
|
||||
Nous savons que ce problème est résoluble et donc ***décidable***
|
||||
|
||||
Son algorithme est très simple : il suffit de diviser par 2 et d'observer le reste de la division : si celui ci est égal à 0, alors il s'agit d'un nombre pair. Sinon, ce nombre est impair.
|
||||
|
||||
On peut maintenant écrire notre algorithme sous forme de langage python :
|
||||
|
||||
|
||||
```python
|
||||
def est_pair(n):
|
||||
''' Renvoie un prédicat exprimant le résultat de n modulo 2
|
||||
Si le reste est nul, alors le prédicat est vrai et le nombre n est pair, sinon, il est impair.
|
||||
|
||||
'''
|
||||
return n % 2 == 0
|
||||
```
|
||||
|
||||
```python
|
||||
>>>est_pair(42)
|
||||
>>>True
|
||||
>>>est_pair(113)
|
||||
>>>False
|
||||
```
|
||||
|
||||
|
||||
|
||||
Si ce code fonctionne, il ne faut pas oublier une chose : ça n'est pas la seule solution existante au problème : puisque ce problème est décidable, vous pouvez écrire votre propre algorithme qui fera tout aussi bien !
|
||||
|
||||
Par exemple :
|
||||
|
||||
|
||||
```python
|
||||
def est_pair2(n):
|
||||
|
||||
if (n % 2) == 0:
|
||||
return("{0} est Pair".format(n))
|
||||
else:
|
||||
return("{0} est Impair".format(n))
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
>>>est_pair2(113)
|
||||
>>>'113 est Impair'
|
||||
>>>est_pair2(42)
|
||||
>>>'42 est Pair'
|
||||
```
|
||||
|
||||
|
||||
|
||||
Nous avons bien la preuve que le problème " Peut-on prouver qu'un nombre est pair" est bel et bien décidable.
|
||||
|
||||
### Tous les problèmes sont ils décidables?
|
||||
|
||||
Et bien non ! Disons le tout de suite, il existe un nombre de problèmes que l'ont ne peut résoudre par un simple algorithme. On parlera de ***Problèmes Indécidables*** !
|
||||
|
||||
La question qui se pose à nous est de savoir comment reconnaitre un problème indécidable.
|
||||
|
||||
Et à l'heure actuelle, nous ne disposons pas de machine magique permettant de nous donner cette information.
|
||||
|
||||
Pour déduire l'indécidabilité d'un programme, il faut un algorithme répondant à ce problème et également la preuve qu'il se termine.
|
||||
|
||||
En mathématiques, on utilise le ***problème de l'arrêt***
|
||||
|
||||
### Un peu plus d'histoire...
|
||||
|
||||
En 1931, Kurt Gödel, mathématicien et logicien autrichien, énonce son théorème d'incomplétude.
|
||||
|
||||
Il y établit qu'une théorie suffisante pour y démontrer les théorèmes de base de l'arithmétique -la partie des mathématiques qui s'occupe des nombres, en opposition à la géométrie - est nécessairement incomplète, au sens où il existe des énoncés qui n'y sont ni démontrables, ni réfutables . On parle alors d'énoncés indécidables dans la théorie.
|
||||
|
||||
Note : Il s'agit de la définition Wikipédia
|
||||
|
||||
Il parle également d'***Axiomes***
|
||||
|
||||
Un axiome est une proposition non démontrée que l'on va utiliser pour tenter de résoudre un problème.
|
||||
|
||||
C'est à dire qu'on va partir d'une hypothèse qu'on supposera vraie, pour essayer d'aller au bout du raisonnement.
|
||||
|
||||
Cela nous ramènera donc à des décisions logiques qui en découleront.
|
||||
|
||||
### Mais si le postulat de base est éronné ?
|
||||
|
||||
C'est tout le principe : s'il est éronné, alors il faut tester son exact opposé : celà prend du temps.
|
||||
|
||||
Et enfin, en testant l'opposé, on pourra savoir si notre problème est décidable ou pas !
|
||||
|
||||
Revenons à notre problème d'arrêt : Il s'agit d'un problème de décision qui determine si le programme s'arrête ou non. Pratique ? C'est exactement ce que l'on cherche justement.
|
||||
|
||||
Oui mais :En 1936, Alan Turing démontre son indécidabilité.
|
||||
|
||||
#### Attendez, le programme qui determine l'indécidabilité est lui même indécidable ??
|
||||
|
||||
Eeh oui, c'est incroyable mais juste : ironique n'est ce pas ? On peut même dire *absurde*
|
||||
|
||||
En effet, on va user d'un raisonnement par l'absurde pour montrer que ce qu'on pense vrai est en réalité faux.
|
||||
|
||||
En supposant que ce que l'on veut vrai, soit faux, avec une pensée logique, on peut et doit, aboutir à une contradiction qui établira que ce que l'on pense donc vrai, est faux.
|
||||
|
||||
#### Vous suivez toujours ?
|
||||
|
||||
Supposons que l'on puisse écrire une fonction arret, capable de dire si une fonction programme va s'arrêter dans tous les cas ou s'il existe des cas où elle ne s'arrête pas.
|
||||
|
||||
Il n'est, dans notre exemple, absolument pas certain qu'une telle fonction existe.
|
||||
|
||||
Nous allons dans un premier temps, créer une fonction qui nous servira de cobaye dans notre fonction absurbe de programme d'arrêt.
|
||||
|
||||
|
||||
```python
|
||||
def arret_programme(programme, x):
|
||||
'''retourne vrai si le programme s'arrête ou non selon le paramètre x
|
||||
'''
|
||||
predicat = ...
|
||||
if predicat:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
```
|
||||
|
||||
Dans le code ci dessus, si notre condition est vraie, alors le programme renverra True.
|
||||
Sinon, il renverra False.
|
||||
|
||||
Jusqu'ici, tout est logique, et c'est comme cela que la plupart des programmes fonctionne.
|
||||
|
||||
Maintenant, définissons notre fonction absurde
|
||||
|
||||
|
||||
```python
|
||||
def absurde(programme):
|
||||
if arret_programme(programme,x):
|
||||
while True:
|
||||
continue
|
||||
else:
|
||||
return True
|
||||
```
|
||||
|
||||
Si on analyse ce que l'on vient d'écrire : Quand la fonction arret_programme peut s'arrêter, la fonction absurde va lui permettre de boucler à l'infini !
|
||||
|
||||
Mais si le test se révèle négatif, on renvoit True et arretons donc la fonction!
|
||||
|
||||
Nous venons donc de prouver l'impossible. Pas mal non ?
|
||||
|
||||
|
||||
#### Quand le possible et l'impossible se mélangent...Possimpible ?
|
||||
|
||||
Turing prouve donc qu'il n'est pas possible d'inventer une fonction prouvant qu'une autre donnée se termine.
|
||||
|
||||
Si la machine ne peut nous aider, il vous faudra donc, en tant qu'humain, toujours assurer le contrôle de votre code.
|
||||
|
||||
### Question : Que peut-on en déduire ?
|
||||
|
||||
On peut retenir deux choses de notre exemple : Le fameux théorème de Kurt Gödel, qui traite de l'indécidabilité, n'est pas vérifiable puisque qu'on ne peut vérifier la décidabilité de tous les sytèmes, dès lors que la fonction qui doit nous y aider n'est elle même pas décidable !
|
||||
|
||||
Pour comprendre la démonstration de tout cela, il nous aura fallu analyser la démonstration en elle même, et non pas essayer de démontrer ce qu'elle prouve. Ce qui laisse perplexe quant à la veracité de certaines affirmations.
|
||||
|
||||
Enfin, on peut se demander une chose. Puisque nous avons une donnée en entrée d'une fonction, et une donnée en sortie...Une fonction ne serait-elle pas uniquement que données ?
|
||||
|
||||
Finalement, quand on regarde un programme, qu'est ce que c'est ? Exemple en python : un fichier texte avec une extension.
|
||||
Sous un système unix, absolument tous les fichiers ne sont que du texte ! Pire : dans notre exemple, nous utilisons un programme comme donnée d'un autre programme !
|
||||
|
||||
Et si tout est donnée, alors cela expliquerait pourquoi la logique tient une si grande importance dans notre environnement.
|
||||
|
||||
--------
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
57
Calculabilité/TURING.md
Normal file
@@ -0,0 +1,57 @@
|
||||
## Machine de Turing
|
||||
|
||||
Cette machine est constituée :
|
||||
|
||||
- D' un **ruban infini** divisé en cases consécutives. Chaque case contient un symbole d'un *alphabet*. L'alphabet contient un symbole spécial appelé « symbole blanc », et un ou plusieurs autres symboles. Le ruban est supposé être de longueur infinie vers la gauche ou vers la droite, en d'autres termes la machine doit toujours avoir assez de longueur de ruban pour son exécution. On considère que les cases du ruban contiennent par défaut le « symbole blanc » .
|
||||
|
||||
- Une **tête de lecture/écriture** (ci-dessous le **`V`**) qui peut lire et écrire les symboles sur le ruban, et se déplacer vers la gauche ou vers la droite du ruban
|
||||
|
||||
- Un **registre d'état** qui mémorise l'état courant de la machine de Turing. Le nombre d'états possibles est toujours fini, et il existe un état spécial appelé « état de départ » qui est l'état initial de la machine avant son exécution.
|
||||
|
||||
- Une **table d'actions** qui indique à la machine quel symbole écrire sur le ruban, comment déplacer la tête de lecture (vers la droite ou la gauche), et quel est le nouvel état, en fonction du symbole lu sur le ruban et de l'état courant de la machine. Si aucune action n'existe pour une combinaison donnée d'un symbole lu et d'un état courant, la machine s'arrête.
|
||||
|
||||
|
||||
|
||||
**Exemple : voici l'algorithme permettant d'ajouter 1 à un nombre binaire.**
|
||||
|
||||
Choisissez un nombre binaire et écrivez le à droite de la tête de lecture (par exemple 101).
|
||||
|
||||
| | | | | | | | | | | V | | | | | | | | | |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| | | | | | | | | | | | 1 | 0 | 1 | | | | | | |
|
||||
|
||||
Réalisez pas à pas l'algorithme ci-dessous :
|
||||
|
||||
- la machine lit chaque case de gauche à droite jusqu'à tomber sur une case vide. Il y a alors deux cas possibles:
|
||||
- Si la dernière case mémorisée dans le registre d'état est un 0 alors la machine se décale d'une case à gauche et écrit 1 puis retourne dans sa position initiale. .
|
||||
- Si la dernière case est un 1, la machine se décale d'une case à gauche et :
|
||||
- si cette case vaut 1, elle écrit 0 puis se décale à gauche et recommence le point précédent.
|
||||
- si cette case vaut 0 ou est vide, elle écrit 1 puis retourne à sa position initiale.
|
||||
|
||||
*Etape 1* : la machine va à droite jusqu'à la première case vide.
|
||||
|
||||
| | | | | | | | | | | | | | | V | | | | | |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| | | | | | | | | | | | 1 | 0 | 1 | | | | | | |
|
||||
|
||||
*Etape 2* : la dernière case lue est ... donc ...
|
||||
|
||||
| | | | | | | | | | | | | | V | | | | | | |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| | | | | | | | | | | | 1 | 0 | 0 | | | | | | |
|
||||
|
||||
*Etape 4* : ...
|
||||
|
||||
| | | | | | | | | | | | | V | | | | | | | |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| | | | | | | | | | | | 1 | 1 | 0 | | | | | | |
|
||||
|
||||
*Etape 5* : ...
|
||||
|
||||
| | | | | | | | | | | V | | | | | | | | | |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| | | | | | | | | | | | 1 | 1 | 0 | | | | | | |
|
||||
|
||||
Vous trouverez [sur ce site](http://zanotti.univ-tln.fr/turing/turing.php) un simulateur d'une machin de de Turing si vous souhaitez aller plus loin.
|
||||
|
||||
ll faut garder à l'esprit que la machine de Turing est un modèle universel de calcul et qu'elle peut calculer tout ce que n'importe quel ordinateur physique peut calculer (aussi puissant soit-il). Inversement, ce qu'elle ne peut pas calculer ne peut l'être non plus par un ordinateur. Elle résume donc de manière saisissante le concept d'*ordinateur* et constitue un support idéal pour raisonner autour de la notion d'*algorithme* de *calcul* ou de *démonstration*. En terminale, nous étudierons plus en détail le concept de calculabilité.
|
||||
BIN
Calculabilité/assets/bo.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
Calculabilité/assets/diagramme.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Calculabilité/machine_de_turing.mp4
Normal file
16
Processus/CORRIGE.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# TD Gestion des processus et des ressources corrigé
|
||||
|
||||
------
|
||||
|
||||
## 1. QCM
|
||||
|
||||
1. a.
|
||||
2. a.
|
||||
3. c.
|
||||
4. c.
|
||||
5. c.
|
||||
|
||||
## 2. Questions
|
||||
|
||||
1. Grâce à l'ordonnancement et le découpage des programmes en processus.
|
||||
2. Un processus élu est en cours d'exécution, un prêt est en file d'attente dans l'ordonnanceur.
|
||||
46
Processus/EXERCICES.md
Normal file
@@ -0,0 +1,46 @@
|
||||
## 1. QCM
|
||||
|
||||
1. Le terminal, interpréteur de commande :
|
||||
|
||||
a. Exécuter les commandes
|
||||
|
||||
b. Est un tableau de bord de l'OS
|
||||
|
||||
c. Permet de saisir les données de l'utilisateur
|
||||
|
||||
2. Quelle commande permet sous linux d'afficher les processus :
|
||||
|
||||
a. ps
|
||||
|
||||
b. sh
|
||||
|
||||
c. echo
|
||||
|
||||
3. Un programme peut être exécuté :
|
||||
|
||||
a. Plusieurs fois à la suite par un même processus
|
||||
|
||||
b. Plusieurs fois en même temps par un même processus
|
||||
|
||||
c. Par plusieurs processus
|
||||
|
||||
4. L'ordonnancement permet de :
|
||||
|
||||
a. Exécuter le processus
|
||||
|
||||
b. Changer l'état des processus
|
||||
|
||||
c. Choisi le processus à exécuter
|
||||
|
||||
5. Un interblocage est :
|
||||
|
||||
a. Lorsqu'un programme est exécuté deux fois
|
||||
|
||||
b. Lorsqu'un processus est oublié, le programme est bloqué
|
||||
|
||||
c. Une mauvaise gestion des ressources, bloquant les processus
|
||||
|
||||
## 2. Questions
|
||||
|
||||
1. Expliquer comment cela se fait que l'utilisateur d'un ordinateur à l'impression que les programmes sont exécuté en même temps.
|
||||
2. Quels sont les différences entre les états prêt et élu.
|
||||
179
Processus/README.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Gestion des processus et des ressources
|
||||
|
||||
------
|
||||
|
||||
Nous le savons, un ordinateur possède une architecture de Von Neumann [Rappel 1ère], il y a donc divers composant tels que la mémoire vive, la mémoire 'dure' (Disque dur, SSD...), de périphériques et d'un processeur.
|
||||
|
||||
Le processeur est le 'cerveau' de l'ordinateur et c'est lui qui exécute les tâche de celui-ci.
|
||||
|
||||
Mais alors comment expliquer que notre processeur arrive à ouvrir un navigateur web, un lecteur de musique, télécharger un jeu ou encore envoyer des messages le tout simultanément. (Sans parler des tâches de fond de l'ordinateur)
|
||||
|
||||
Tout ces programmes sont en réalité des lignes immenses de code et le processeur lui agit seul. Il exécute une à une les instructions de chaque programme, mais donne la sensation de tout gérer en même temps.
|
||||
|
||||
> Les processeurs multi-cœurs fonctionnent de la même façon à l'exception près qu'il n'y à pas 1 cœur, mais 4 voir 8 cœurs. Mais au vu des multitudes de programmes tournant en même temps sur la machine, le nombre de cœurs est nettement inferieur.
|
||||
|
||||
## 1. Notion de processus
|
||||
|
||||
Lorsqu'un programme est exécuté, il créer plusieurs processus. En effet, un programme est composé de diverses instructions (lignes de code) qui elles mêmes forment diverses parties (processus) de celui-ci.
|
||||
|
||||
Ces processus sont donc stocker dans une file (tout cela est géré par l'OS [Rappel 1ère]) et sont exécuté un à un.
|
||||
|
||||
*Exemple de répartition de deux programmes par l'OS :*
|
||||
|
||||
<img src="assets/file.png" alt="File" style="width:50%;" />
|
||||
|
||||
Chaque processus possèdent diverses informations stocké en mémoire (dans le PCB (*Process Control Block*)) comme :
|
||||
|
||||
| Nom | Description |
|
||||
| ---------- | ----------------------------------------------------- |
|
||||
| PID | Process ID, identifiant du processus |
|
||||
| Etat | Etat du processus |
|
||||
| Registre | Valeur des registres lors de la dernière interruption |
|
||||
| Mémoire | Emplacement mémoire, allouée par le processeur |
|
||||
| Ressources | Ressources utilisées par le processus. |
|
||||
|
||||
## 2. Gestion des processus
|
||||
|
||||
Nous l'avons vu chaque processus possèdent plusieurs informations. **L'état** d'un processus permet de comprendre comment la file d'exécution est créer et comment celle-ci perdure.
|
||||
|
||||
Il existe 3 états différent :
|
||||
|
||||
- Prêt : Le processus attend d'être exécuté. Il est dans la file d'exécution.
|
||||
- Elu : En cours d'exécution
|
||||
- Bloqué/En attente : Le processus nécessite une ressource non disponible. Tel qu'un emplacement mémoire, une entré/sortie.
|
||||
Lorsque la ressource sera disponible, le processus repassera en état prêt.
|
||||
- On peut imaginer que le processus attend l'intervention de l'utilisateur, ou le chargement d'une ressources (donc d'autres processus), etc.
|
||||
|
||||
Il existe aussi deux autres états :
|
||||
|
||||
- Nouveau : le processus vient d'être crée, il n'est pas encore dans la file d'exécution
|
||||
- Terminé : l'exécution du processus est finie.
|
||||
|
||||
<u>Voici un schéma des différents états :</u>
|
||||
|
||||
<img src="assets/etat.png" style="zoom:50%;" />
|
||||
|
||||
## 3. Interblocage :
|
||||
|
||||
L'interblocage intervient lorsque plusieurs processus sont bloqués les un aux autres.
|
||||
Imaginons deux programme.
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
Accès à la ressource A
|
||||
Accès à la ressource B
|
||||
....
|
||||
Libération de ressource B
|
||||
Libération de ressource A
|
||||
```
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource B
|
||||
Accès à la ressource A
|
||||
....
|
||||
Libération de ressource A
|
||||
Libération de ressource B
|
||||
```
|
||||
|
||||
### 3. 1. Un exemple d'ordonnancement
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
Accès à la ressource A
|
||||
Accès à la ressource B
|
||||
```
|
||||
|
||||
- Le processus 1 à commencé, via un premier processus. Afin de faire tourner tous les programmes 'en même temps' il repasse dans la file d'exécution
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource B
|
||||
....
|
||||
```
|
||||
|
||||
- Ici l'accès ne peut se faire, le programme 2 passe donc en état **Bloqué**
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
....
|
||||
Libération de ressource B
|
||||
Libération de ressource A
|
||||
```
|
||||
|
||||
- Le programme 1 se termine et donc libère A et B
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource B
|
||||
Accès à la ressource A
|
||||
....
|
||||
Libération de ressource A
|
||||
Libération de ressource B
|
||||
```
|
||||
|
||||
- Le programme 2 peut donc s'exécuter normalement
|
||||
|
||||
### 3. 2. Mauvais ordonnancement :
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
Accès à la ressource A
|
||||
```
|
||||
|
||||
- Le programme 1 créer un premier processus, qui appelle la ressource A
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource B
|
||||
```
|
||||
|
||||
- le programme 2 créer un premier processus, qui appelle la ressource B
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
Accès à la ressource B
|
||||
```
|
||||
|
||||
- Le programme 1 attend la ressource B utilisée par le programme 2 et passe en état bloqué.
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource A
|
||||
```
|
||||
|
||||
- Le programme 2 attend la ressource A utilisée par le programme 1 et passe en état bloqué.
|
||||
|
||||
Ici les deux programmes sont en état bloqué car chacun attend la ressource de l'autre. Il y a interblocage et donc aucuns des programmes ne peut s'exécuter.
|
||||
|
||||
## 4. En pratique
|
||||
|
||||
### 4. 1. Windows
|
||||
|
||||
Sous windows il est possible de voir les processus en cours d'exécution grâce au **gestionnaire de tâche**. Celui-ci est accessible grâce aux touches Ctrl+ Maj+Echap.
|
||||
Il suffit ensuite d'aller dans l'onglet détail et on obtient tous les processus.
|
||||
|
||||
<img src="assets/liste_processus_windows.png" style="width:60%;" />
|
||||
|
||||
Nous retrouvons bien, l'**état**, le **PID**, la **mémoire occupée**
|
||||
|
||||
### 4. 2. Linux
|
||||
|
||||
Sous linux, il suffit d'accéder au terminal. Et d'y écrire la commande **ps**, il est possible de voir les **PID** et **PPID** (processus parent)
|
||||
|
||||

|
||||
|
||||
### 4.3 MacOs
|
||||
|
||||
MacOs étant un système Unix, (dérivé de BSD ici) on retrouve les mêmes commandes que sous linux en grande partie.
|
||||
Pour voir les processus, ici, on utilisera plutôt **TOP** (dispo sous linux également donc).
|
||||
|
||||
<img src="assets/top.png" alt="top" style="zoom:50%;" />
|
||||
|
||||
---------
|
||||
|
||||
Auteurs : Florian Mathieu, Timothée Decoster, Enzo Frémaux
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
BIN
Processus/assets/bo.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
Processus/assets/etat.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
Processus/assets/file.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
Processus/assets/liste_processus_windows.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
Processus/assets/ps_aux.webp
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
Processus/assets/top.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
337
Recherche_textuelle/README.md
Normal file
@@ -0,0 +1,337 @@
|
||||
## Recherche Textuelle
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
> En informatique, il est peut-être utile et interessant de determiner la présence ou non d'un motif au sein d'un texte. Par exemple quand vous cherchez un mot précis dans un long document, si vous voulez vous entrainer pour des chiffres et des lettres...
|
||||
|
||||
On se donne un texte et un motif représentés en Python par des chaînes de caractères (*type str*). La question est de déterminer la présence ou l'absence de ce motif.
|
||||
|
||||
Le texte et le motif peuvent être représentés par des espaces, lettres, chiffres, différents types de symboles et autres signes de ponctuation.
|
||||
|
||||
> En langage Python, chaque caractère d'une chaîne a un indice permettant d'accéder directement à ce caractère. Les indices vont de *0* à *n -1* si *n* est le nombre de caractères de la chaîne, ou la longueur de la chaîne.
|
||||
|
||||
La fonction ***len*** renvoie la longueur d'une chaîne. Par exemple, si la chaîne *ch* est définie par *ch = "un exemple"* alors ***len**(ch)* a pour longueur 10.
|
||||
|
||||
Il faut faire attention à ne pas oublier de caractère d'espace. Nous utilisons les indices pour obtenir un caractère particulier, par exemple *ch[0]* a pour valeur le caractère "u" et *ch[9]* a pour valeur le caractère "e".
|
||||
|
||||
### 1. Recherche d'un caractère dans un texte
|
||||
|
||||
> Le cas le plus facile à aborder est celui où le motif est un simple caractère. Il s'agit d'une recherche linéaire déjà étudiée en classe de première. Pour le parcours de la chaîne, on peut utiliser une boucle ***while*** ou une boucle ***for***.
|
||||
|
||||
```python
|
||||
def recherche(texte, motif):
|
||||
for car in texte:
|
||||
if car == motif:
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
Si une des valeur successives de la variable ***car*** est égale à la valeur de la variable ***motif*** alors la fonction renvoie ***True*** et la fonction est interrompue. Si tous les caractères du texte sont examinés et que la bouclle n'est pas interrompue, la fonction renvoie ***False***.
|
||||
|
||||
Nous remplaçons l'instruction ***return True*** par ***return i*** si nous souhaitons obtenir la place du caractère dans le texte. La fonction renvoie alors la place du caractère s'il a été trouvé et rien sinon (donc la valeur ***None***).
|
||||
|
||||
```python
|
||||
def recherche (texte, motif):
|
||||
for i in range (len(texte)):
|
||||
if texte[i] == motif:
|
||||
return i
|
||||
```
|
||||
|
||||
#### Coût
|
||||
|
||||
Le coût de cette recherche est linéaire en la longueur de la chaîne, en effet, si *n* est la longueur de la chapine, on procède à *n* comparaisons dans le pire des cas, celui où le caractère cherché n'est pas trouvé avant la fin du texte.
|
||||
|
||||
### 2. Recherche naïve d'un motif dans un texte
|
||||
|
||||
> On parle de recherche naïve car c'est l'une des premières idées qui peut venir à l'esprit
|
||||
|
||||
- On recherche la présence du premier caractère du motif dans le texte
|
||||
- Si on le trouve, on vérifie si les caractères suivants du motif coïncident avec ceux du texte
|
||||
- Si tous les caractères coïncident, alors le motif est trouvé, sinon, on reprendre la recherche du premier caractère.
|
||||
|
||||
Cet algorithme est implémenté dans le programme suivant, où nous pouvons remplacer l'instruction ***return j*** par ***return True*** si seulement la présence ou non du motif dans le texte nous intéresse.
|
||||
|
||||
|
||||
|
||||
```python
|
||||
def recherche(texte, motif):
|
||||
n = len(texte)
|
||||
m = len(motif)
|
||||
for j in range(n - m +1):
|
||||
i = 0
|
||||
while i < m and texte [j + i] == motif [i]:
|
||||
i = i + 1
|
||||
if i == m :
|
||||
return j
|
||||
```
|
||||
|
||||
| indice j | 0 | 1 | ... | ... | j | | | | ... | ... |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| texte | u | n | | | e | x | e | m | | |
|
||||
| | | | | | ↕ | ↕ | ↕ | | | |
|
||||
| motif | | | | | e | x | e | r | | |
|
||||
| indice i | | | | | 0 | 1 | 2 | 3 | | |
|
||||
|
||||
|
||||
|
||||
#### Coût
|
||||
|
||||
Si *n* est la longueur du texte et *m* la longueur du motif recherché, alors la boucle *for* est parcourue (*n-m+1*) fois.
|
||||
|
||||
En effet la recherche du premier caractère du motif s'arrête lorsqu'il ne reste plus assez de place dans le texte pour placer ce motif.
|
||||
Dans le pire des cas, la boucle interne *while* est parcourue au plus *m* fois, pour tester chaque caractère du motif.
|
||||
|
||||
> Le nombre total de comparaisons entre caractères est donc majoré par *m(n - m + 1)*. Par exemple, si *m = 5* alors on peut dire que le nombre total de comparaisons est majoré par *5n*. Le nombre *m* est compris entre *0 et n* et on peut donc montrer que la valeur maximale du produit *m(n - m + 1)* est *m<sup>2</sup> + m = (n<sup>2</sup> + 2n) / 4* .
|
||||
|
||||
|
||||
|
||||
```python
|
||||
def recherche2(texte, motif):
|
||||
m = len(motif)
|
||||
n = len(texte)
|
||||
i = 0
|
||||
j = 0
|
||||
while i < m and j < n :
|
||||
if motif [i] != texte[j]:
|
||||
|
||||
j = j - i + 1
|
||||
i = 0
|
||||
else:
|
||||
i += 1
|
||||
j += 1
|
||||
if i >= m:
|
||||
return j - m
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### Exemple
|
||||
|
||||
Le texte est "***abcababcabc***" et le motif recherché est "***abcabc***". Les caractères sont comparés un par un depuis lde début, de la gauche vers la droite.
|
||||
|
||||
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | ↕ | ↕ | ↕ | ↕ | ↕ | ↕ | | | | | |
|
||||
| Motif | a | b | c | a | b | **c** | | | | | |
|
||||
| Indice i | 0 | 1 | 2 | 3 | 4 | 5 | | | | | |
|
||||
|
||||
Après six comparaisons de caractères, nous avons un échec (lettres en gras). Le motif est alors décalé d'une unité vers la droite.
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ----- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | **b** | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | ↕ | | | | | | | | | |
|
||||
| Motif | | **a** | b | c | a | b | c | | | | |
|
||||
| Indice i | | 0 | 1 | 2 | 3 | 4 | 5 | | | | |
|
||||
|
||||
Ici, c'est un échec dès la première compraison, il faut donc à nouveau nous décaler vers la droite.
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ----- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | **c** | a | b | **a** | b | c | a | b | c |
|
||||
| | | | ↕ | | | | | | | | |
|
||||
| Motif | | | **a** | b | c | a | b | c | | | |
|
||||
| Indice i | | | 0 | 1 | 2 | 3 | 4 | 5 | | | |
|
||||
|
||||
Idem ici, on redécale.
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | ↕ | ↕ | ↕ | | | | | |
|
||||
| Motif | | | | a | b | **c** | | | | | |
|
||||
| Indice i | | | | 0 | 1 | 2 | 3 | 4 | 5 | | |
|
||||
|
||||
Ici, echec à la troisième comparaison. On décale vers la droite.
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ----- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | **b** | **a** | b | c | a | b | c |
|
||||
| | | | | | ↕ | | | | | | |
|
||||
| Motif | | | | | **a** | b | c | a | b | c | |
|
||||
| Indice i | | | | | 0 | 1 | 2 | 3 | 4 | 5 | |
|
||||
|
||||
Encore une fois, un échec à la première comparaison. Le motif est décalé d'une unité vers la droite.
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | a | b | c | a | b | c |
|
||||
| | | | | | | ↕ | ↕ | ↕ | ↕ | ↕ | ↕ |
|
||||
| Motif | | | | | | a | b | c | a | b | c |
|
||||
| Indice i | | | | | | 0 | 1 | 2 | 3 | 4 | 5 |
|
||||
|
||||
Il nous aura donc fallu dix-huit comparaisons pour trouver le motif. Si le dernier caractère du texte n'était pas un "***c***", nous aurions appris l'absence du motif après le même nombre de comparaisons.
|
||||
|
||||
|
||||
|
||||
### 3. Pré-traitement du motif
|
||||
|
||||
> On peut remarquer qu'il n'est pas judicieux, lorsqu'une comparaison n'est pas trouvée, de décaler le motif d'une seule unité.
|
||||
>
|
||||
> Par exemple, après les six premières comparaisons, on constate que les cinq premiers caractères du texte sont les cinq premiers du motif. Donc, en décalant, on va forcément être amené à comparer le début du motif avec une autre partie du motif lui même...
|
||||
>
|
||||
> Les informaticiens Morris et Pratt ont eu séparément l'idée d'effectuer un pré-traitement du motif qui permet de déterminer, à partir de quelle place la recherche doit se poursuivre, et éviter ainsi de controler les mêmes caractères plusieurs fois.
|
||||
|
||||
Reprenons le texte "***abcababcabc***" et le motif "***abcabc***"
|
||||
|
||||
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | ↕ | ↕ | ↕ | ↕ | ↕ | ↕ | | | | | |
|
||||
| Motif | a | b | c | a | b | **c** | | | | | |
|
||||
| Indice i | 0 | 1 | 2 | 3 | 4 | 5 | | | | | |
|
||||
|
||||
Après six comparaisons de caractères, nous avons un échec. Sur les cinq caractères correspondants, les deux premiers sont identiques aux deux derniers. Donc le seul décalage qui peut être intéressant, c'est celui qui aligne ces deux premiers caractères avec les deux derniers. Cette étude, ce pré-traitement du motif, peut être réalisée avant de commencer la recherche.
|
||||
|
||||
Le motif est donc décalé de trois unités vers la droite.
|
||||
|
||||
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | ↕ | ↕ | ↕ | | | | | |
|
||||
| Motif | | | | a | b | **c** | a | b | c | | |
|
||||
| Indice i | | | | 0 | 1 | 2 | 3 | 4 | 5 | | |
|
||||
|
||||
Les comparaisons commencent donc au troisième caractère pour lequel nous avons un échec ici.
|
||||
|
||||
Il n'est pas interessant de décaler uniquement d'une unité vers la droite. Le caractère est un "a" et nous savons parfaitement où se trouve ce caractère dans le motif.
|
||||
|
||||
|
||||
|
||||
| Indice j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | a | b | c | a | b | c |
|
||||
| | | | | | | ↕ | ↕ | ↕ | ↕ | ↕ | ↕ |
|
||||
| Motif | | | | | | a | b | c | a | b | c |
|
||||
| Indice i | | | | | | 0 | 1 | 2 | 3 | 4 | 5 |
|
||||
|
||||
Le nombre total de comparaisons est de treize au lieu de dix-huit pour le programme naïf.
|
||||
|
||||
|
||||
|
||||
```python
|
||||
def morris_pratt(texte, motif):
|
||||
m = len (motif)
|
||||
n = len(texte)
|
||||
i = 0
|
||||
j = 0
|
||||
sol = [] #tableau pour stocker les solutions
|
||||
s = traitement (motif) #modification du programme naïf recherche
|
||||
while i < m and j < n :
|
||||
if i >= 0 and motif[i] != texte[j] :
|
||||
i = s[i]
|
||||
else:
|
||||
i += 1
|
||||
j += 1
|
||||
if i >= m : #Si le motif est présent
|
||||
sol.append(j-m) # La position dans le texte est ajoutée à la liste
|
||||
i = 0 # Une nouvelle recherche commence après le motif trouvé
|
||||
return sol
|
||||
```
|
||||
|
||||
Ici, par rapport à recherche2, on modifie les instructions dans le cas où ***motif[i]*** est différent de ***texte[j]***
|
||||
|
||||
Dans le programme naïf, les indices i et j sont modifiés par ***j = j - i + 1*** pour décaler le motif d'une unité et ***i = 0*** pour recommencer les comparaisons à partir du premier caractère du motif.
|
||||
|
||||
Dans ce nouveau programme, j n'est pas modifié. On reste donc sur le caractère posant problème, on ne revient pas en arrière.
|
||||
|
||||
Pour la valeur de i, qui permet d'effectuer le bon décalage, on effectue une fois le traitement s = traitement (motif), s est alors un tableau, et s[i] est la nouvelle valeur de i.
|
||||
|
||||
|
||||
|
||||
### 4. Algorithme de Boyer Moore
|
||||
|
||||
> Boyer, mathématicien et informaticien, et Moore, informaticien, sont tous les deux de l'université d'Austin au Texas. L'algorithme qui porte leurs noms a été inventé en 1977.
|
||||
>
|
||||
> Pour observer le comportement de l'algorithme, on peut aller [ici](https://www.cs.utexas.edu/users/moore/best-ideas/string-searching/fstrpos-example.html)
|
||||
|
||||
Le principe général des algorithmes de recherche textuelle est de comparer un motif à certaines parties du texte, le motif se décalant vers la droite après chaque échec.
|
||||
|
||||
Comme cela est pratiqué avec l'algorithme de Morris et Pratt, le calcul du décalage d'obtient par un pré-traitement du motif. La différence fondamentale avec ce que l'on a vu précédémment, est que ***la comparaison entre le motif et une partie du texte se fait de droite à gauche en commençant par la fin du motif***.
|
||||
|
||||
En procédant ainsi, un type de décalage est articulièrement intéresssant : à la premiere différence constatée, on décale le motif vers la droite de manière à faire coïncider le caractère du texte concerné avec un caractère du motif. Si ce n'est pas possible, alors on décale le motif après le caractère.
|
||||
|
||||
|
||||
|
||||
#### Exemple
|
||||
|
||||
Reprenons le motif "***abcabc***" et le texte "**abcababcabc**".
|
||||
|
||||
Notons ***s*** l'indice d'un caractère du texte (s pour shift, soit décalage en anglais)
|
||||
|
||||
|
||||
|
||||
| Indice s | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | | | ↕ | | | | | |
|
||||
| Motif | a | b | c | a | b | **c** | | | | | |
|
||||
| Indice i | 0 | 1 | 2 | 3 | 4 | 5 | | | | | |
|
||||
|
||||
La comparaison commence donc par la fin du motif, de droite à gauche. Nous avons un échec dès la première tentative : on décale donc le motif de manière à faire coïncider le caractère "a" du texte avec sa dernière occurence dans la partie du motif non utilisée dans cette comparaison, soit "abcab".
|
||||
|
||||
On décale donc le motif de deux unités vers la droite.
|
||||
|
||||
|
||||
|
||||
| Indice s | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | | | | | | | | |
|
||||
| Motif | | | a | b | c | a | b | c | | | |
|
||||
| Indice i | | | 0 | 1 | 2 | 3 | 4 | 5 | | | |
|
||||
|
||||
Reprenons les comparaisons à partir de la fin du motif
|
||||
|
||||
|
||||
|
||||
| Indice s | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | | ↕ | ↕ | ↕ | ↕ | | | |
|
||||
| Motif | | | a | b | c | a | b | c | | | |
|
||||
| Indice i | | | 0 | 1 | 2 | 3 | 4 | 5 | | | |
|
||||
|
||||
Ici, on rencontre donc un échec après quatre comparaisons. Nous décalons le motif de nouveau, afin de faire coïncider le caractère "b" du texte avec sa dernière occurence dans la partie du motif non utilisée, soit "ab"
|
||||
|
||||
|
||||
|
||||
| Indice s | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | | | | | | | | |
|
||||
| Motif | | | | a | b | c | a | b | c | | |
|
||||
| Indice i | | | | 0 | 1 | 2 | 3 | 4 | 5 | | |
|
||||
|
||||
On recommence donc à comparer depuis l'élément le plus à droite. C'est un échec après une comparaison. le caractère du texte est un "a" et il faut donc décaler de nouveau le motif pour faire correspondre la dernière occurence dans la partie non utilisée ici du motif.
|
||||
|
||||
|
||||
|
||||
| Indice s | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|
||||
| -------- | ---- | ---- | ---- | ---- | ---- | ----- | ---- | ---- | ---- | ---- | ---- |
|
||||
| Texte | a | b | c | a | b | **a** | b | c | a | b | c |
|
||||
| | | | | | | ↕ | ↕ | ↕ | ↕ | ↕ | ↕ |
|
||||
| Motif | | | | | | a | b | c | a | b | c |
|
||||
| Indice i | | | | | | 0 | 1 | 2 | 3 | 4 | 5 |
|
||||
|
||||
Il nous faudra ici six comparaisons finales pour affirmer la présence du motif au sein du texte. Le nombre total de comparaisons est alors de douze.
|
||||
|
||||
Remarque : si la dernière lettre du texte n'était pas un "c", alors nous n'aurions eu besoin que d'une seule comparaison au lieu de six pour affirmer l'absence du motif, soit sept comparaisons au total.
|
||||
|
||||
|
||||
|
||||
BIN
Recherche_textuelle/assets/bo.png
Normal file
|
After Width: | Height: | Size: 54 KiB |