Jean-Jacques BOURDIN

Université Paris 8
Labo IA, Dépt. Informatique
2, rue de la Liberté
93526 Saint-Denis Cedex
FRANCE

Tél : (+33/0) 1 49 40 66 80
E-mail : Jean-Jacques.BourdinNOSPAM@ai.univ-paris8.fr (enlever le NO Spam)



Le dernier partiel écrit aura lieu le 2/9/2020 en amphi B1. Entre 14h et 16h.

Tout étudiant qui n'a pas encore rendu son propre projet doit prendre contact au plus vite avec l'enseignant sauf à accepter d'être compté absent.

À partir du 19 août, 14h, de nouvelles séances de révision seront données sur le serveur Discord (ou sur un BBB). Les liens seront donnés sur cette page.

Dans tous les cas je reste disponible par mail pour toute question.

Attention, compte tenu de ce que vous avez fait au second semestre, le partiel ne contiendra pas de questions sur C ni Prolog.


Une note va donc être affichée sur votre ENT. Elle tient compte de votre second partiel pour ceux qui l'ont passé ou simplement du premier.

Dans tous les cas, il sera possible de passer un "second partiel" à la fin des cours de second semestre, à une date que nous fixerons via un sondage en ligne.

Ce nouveau partiel ne pourra pas comprendre de questions sur C, Prolog ou Java, puisque les cours de programmations impérative et logique vous auront fait progresser dans ces domaines. Il y aura donc des questions concernant les langages suivants :


Méthodologie de la Programmation

Septembre-décembre 2019

  1. Présentation
  2. Essayons !
  3. Comparons !
  4. Scriptons !
  5. Le texte de votre premier partiel à afficher avec acroread.

  6. Les énoncés des projets
  1. Présentation

    • L'université, la formation

    • Ce cours

    • Mail

      Dans tout ce cours il faudra, souvent, m'envoyer des messages par email. Vous devrez utiliser votre compte étudiant (etud.univ-paris8.fr), de façon à ce que je puisse vous répondre facilement. Les pièces jointes sont autorisées à condition que les fichiers portent un suffixe cohérent ("exo.l" si c'est du lisp par exemple). Les messages sans sujet peuvent ne pas être lus.

      Une série de raccourcis est disponible sous emacs, vous en trouverez quelques exemples soit ici , soit en tapant Esc x puis "describe-bindings" sous emacs.

      Pour "lancer emacs" faire  :
        $ emacs prog.l &
      
      où $ est le prompt que le système vous adresse.
    • Informatique ?

    • Histoire

    • Principes et Classification des langages

  2. Essayons !

    1. Lisp, Scheme, Syntaxe

      1. syntaxe

        (function parameter_1 parameter_2 parameter_3 ... parameter_n)
        (+ 3 2) => 5
        
      2. Facile

        Avec Drracket il suffit de lancer DrRacket, donc de choisir l'application racket dans le menu application.
        Dans la fenêtre qui s'ouvre, deux parties, en haut doit être écrit

        #lang racket
        et dans celle du bas, vous pouvez demander des évaluations et racket les exécute.

        >(- 5 2)
        3
        > (+ 5 (* 2 6))
        17
        > 
        
      3. Premiers programmes

        (define (foisquatre n)
            (* n 4))
        (define (carre n)
            (* n n))
        (define (cube n)
            (* n (* n n)))
        
        Faites maintenant :
        • une fonction qui renvoie le double d'un nombre.
        • une fonction qui renvoie le triple d'un nombre.
        • une fonction qui renvoie la puissance cinq d'un nombre.
      4. Réutilisation
        Éditez votre fichier, sauvegardez-le (par exemple avec le nom premprog.l), lancez lisp. Tapez
        (load "premprog.l")
        
        Lisp répond par son promopt >. Vous pouvez alors vous servir de tout ce qui est défini dans le fichier. Par exemple pour demander un calcul (+ 3 5) ou l'évaluation d'une fonction :
        >(carre 5)
        25
        >(carre 6)
        36
        >(cube 5)
        125
        >
        
        Plus tard, vous devrez quitter racket en choisissant "quit" dans le menu.
      5. Et sinon ?

        Plus grand de deux valeurs

        (define (plgd2 a b)
          (if (< a b) 
              b 
              a))
        

        Exercices à faire et à valider sur ordinateur.

        1. puissance4
        2. puissance5
        3. puissance6
        4. plus grand de trois valeurs
        5. plus grand de quatre valeurs
        6. plus grand de cinq valeurs
        7. plus grand de six valeurs
        8. plus petit de trois valeurs
        9. plus petit de quatre valeurs
        10. second plus grand de trois valeurs
        11. second plus grand de quatre valeurs
        12. second plus grand de cinq valeurs
        Exemples de solutions :

        Plus grand de trois valeurs

        (define (plgd3 a b c)
          (if (< a b)
        	  (if (< b c)
        		  c
        		b)
        	(if (< a c)
        		c
        	  a)))
        	       
        Exemples :

        Plus grand de quatre valeurs

        (define (plgd4 a b c d)
          (if (< a b)
        	  (if (< b c)
        		  (if (< c d)
        			  d
        			c)
        		(if (< b d)
        			d
        		  b))
        	(if (< a c)
        		(if (< c d)
        			d
        		  c)
        	  (if (< a d)
        		  d
        		a))))
        

        Plus grand de quatre valeurs, again...

        (define (plg4 a b c d)
          (plgd2 (plgd2 a b) (plgd2 c d)))
        
    2. Récursivité
      1. Définition
      2. Méthode
        Pour utiliser la récursivité il faut :
        1. une borne
        2. une règle générale
        3. vérifier que la règle générale avance vers la borne.
      3. Fonctions simples
        Nous verrons ici des fonctions numériques simples (la somme des n premiers entiers, la factorielle), puis leur transformation pour obtenir des fonctions un peu plus complexes, comme la somme des carrés de n premiers entiers.
        (define (som n)
            (if (= n 0)
                0
                (+ n (som (- n 1)))))
        (define (fac n)
            (if (< n 2)
                1
                (* n (fac (- n 1)))))
        
        Vous devrez ensuite faire une série d'exercices :
        • Produit des carrés des n premiers entiers
        • Produit des cubes des n premiers entiers
        • Produit des puissances 4 des n premiers entiers
        • Soustraction par additions et soustractions de 1.
        • Division entière par soustractions successives.
        • Reste de la division entière par soustractions successives.
        • pgcd.
        • Produit de leur propre puissance des n premiers entiers

          0^0+1^1+2^2+3^3+...+n^n
        • Somme des puissances n des n premiers entiers
          0^n+1^n+2^n+3^n+...+n^n
        • Somme des puissances p des n premiers entiers
          0^p+1^p+2^p+3^p+...+n^p

        Exemple d'erreur :
        (define (div a b)
          (if (= a b)
              1
              (+ 1 (div (sous a b) b))))
        > (div 10 5)
        2
        > (div 11 5)
        . Interactions disabled; out of memory
        
        Vous l'avez essayé et ça vous a plu. Je l'ai testé et détesté !
        il ne vous reste plus qu'à corriger.
      4. Fibonacci.

      5. Récursivité terminale
        Comment transformer une récursivité en terminale ? En ajoutant un paramètre dans lequel seront faits les calculs intermédiaires.
        Exemple :
        (define (somme n)
           (somrt n 0))
        (define (somrt n acc)
           (if (= n 0)
               acc
               (somrt (- n 1) (+ n acc))))
        
        Reprendre en récursivité terminale tous les exercices faits jusqu'ici.
        Exemple d'erreur : faire la multiplication par additions successives
        ;Multiplication de deux valeurs en récursivite terminale
        (define (mulrtaux a b acc)
          (if (= a 0)
              (* b acc)  ; ceci n est pas une addition, Hors Sujet
              (mulrtaux (- a 1) b (+ acc 1))))
        (define (mulrt a b)
          (mulrtaux a b 0))
        

        Et pourtant ça commençait bien, non ?

        Reste à refaire tous les exercices récursifs en récursivité terminale, y compris Fibonacci.

        (define (multrt a b)
          (multrtaux a b 0))
        ; il faut bien 0 puisqu on va faire des additions
        (define (multrtaux a b acc)
          (if (= a 0)
             acc
             (multrtaux (- a 1) b (+ b acc))))
        ; et où est la difficulté ?
        

      Images en Lisp

      Voici un programme qui affiche des traits qui forment un visage.

      (define (ee) (load "Prog/Lisp/gra.l"))
      (require graphics/graphics)
      
      (define (findu port)
        (close-viewport port)
      ; viewport disappears
        (close-graphics)
      ; again, nothing appears to happen, but
      ; unclosed viewports (if any) would disappear
      )
      
      (define (dessine_vis port)
        ((draw-polygon port) (list (make-posn -120 -120)(make-posn 120 -120)(make-posn 120 120)(make-posn -120 120)) (make-posn 140 130))
        ((draw-ellipse port) (make-posn 50 30) 150 180)
        ((draw-ellipse port) (make-posn 70 90) 45 20 "magenta")
        ((draw-solid-ellipse port) (make-posn 80 90) 15 15 "blue")
        ((draw-ellipse port) (make-posn 130 90) 45 20 "magenta")
        ((draw-solid-ellipse port) (make-posn 140 90) 15 15 "blue")
        ((draw-line port) (make-posn 90 160) (make-posn 150 160) "red")
        ((draw-line port) (make-posn 120 100) (make-posn 120 150))
      )
      (define (face)
        (open-graphics)
      ; nothing appears to happen, but the library is initialized...
        (define viz (open-viewport "visage" 300 300))
        (dessine_vis viz)
        (sleep 20)
        (findu viz)
      ) 
      
      Il faut maintenant s'en servir pour refaire ces fonctions en rendant paramétrique ce visage, c'est-à-dire qu'on puisse lui donner une certaine échelle.
  3. Comparons !

    1. Principes
    2. Impératifs
      1. Python

        1. Premier exemple
          Nous devons essayer Python. Première fonction, offerte par Daniel Goossens :
          def fact(n):
            if n==0: 
               return 1
            else:
               return n*fact(n-1)
          
          print fact(5)
          print fact(6)
          print fact(7)
          

          Pour s'en servir, une fois ce programme sera mis dans un fichier exo.py

          , on se place dans un terminal et on tape :

          dhcp17.ai.univ-paris8.fr: python prog.py
          120
          720
          5040
          
          dhcp17.ai.univ-paris8.fr: est le prompt donné par la machine.

          Comme vous le voyez, pour l'utiliser il suffit de demander l'exécution de python fact.py.

          Vous avez quelques exercices à faire avec python, il suffit de reprendre tout ce que nous avons fait jusqu'ici !


        2. Premiers exercices
          Refaire en Python tous les programmes déjà écrits en Scheme.
        3. Récursivité terminale
          La récursivité est terminale quand, après l'appel, il ne reste aucune évaluation à faire.
          Exemple :
          def restediv (a, b):
               if (a < b):
                  return a
               else:
                  return restediv (a - b, b)
          				
          En général on doit rajouter un paramètre, un accumulateur dans lequel les calculs seront faits.
          Exemple pour la somme des premiers entiers.
          def somt(n):
             if (n < 0):
                 return 0
             return somrt(n,0)
          def somrt (n, acc):
             if (n == 0):
                 return acc
             return somrt(n - 1, acc + n)
          
          somt est une fonction chapeau qui permet d'appeler la fonction somrt qui, elle, fait le travail.
          Refaire toutes les fonctions récursives en recursivité terminale.
        4. Itérations
          Voyons maintenant des fonctions numériques itératives :
          def som(n):
             s = 0
             i = 0
             while (i <= n):
                i = i + 1
                s = i + s
             return s
          print 5,som(5)
          
          

          Si les valeurs obtenues ne vous conviennent pas, vous pouvez corriger un peu le programme...

          Exercices : Vous devez maintenant reprendre toutes vos fonctions récursives (surtout sous la forme récursive terminale) et en faire des fonctions itératives.
          Dès que vous aurez écrit la fonction fib, vous pourrez facilement faire une petite fonction pour s'en servir :
          def essai_fib (n):
              i = 0
              while (i <= n):
                  print i,fib(i)
                  i = i + 1
          
          essai_fib(10)
          

          et maintenant les listes, dites aussi vecteurs

          On appelle vecteur un objet qui est soit vide [], soit la construction d'un élément et d'un vecteur [3,5].

          Première fonction

          def affiche (V):
            for i in V:
              print i
          affiche([7,4,3,2])
          
          Où for sert à mettre dans i, succissivement, chacune des valeurs du vecteur.
          JJBook : python aff.py 
          7
          4
          3
          2
          
          Fonctions à faire :

          Attention, il ne faut pas utiliser d'autres outlis que ceux étudiés en cours.

          1. renvoyer le plus grand élément d'un vecteur.
          2. renvoyer le second plus petit élément d'un vecteur.
          3. faire la somme des éléments d'un vecteur.
          4. compter le nombre d'éléments d'un vecteur.
          5. afficher tous les éléments dans l'ordre inverse.
          6. compter combien d'éléments d'un vecteur sont supérieurs à un x donné. (NB x et le vecteur sont des données de la fonction.)
          7. compter combien d''éléments d'un vecteur sont inférieurs à un x donné.
          8. dire à propos de deux nombres s'ils sont égaux à 1 près (4 et 5, oui, 4 et 7, non).
          9. donner la médiane d'un vecteur.
          Bon, nous essayons de faire ça, et nous voyons que tout passe
          def soml (L):
              nb = len(L)
              i = 0
              s = 0
              while (i < nb):
                  s = s + L[i]
                  i = i + 1
              return s
          print soml([3, 2, 5, 4, 1])
          
          On obtient, bien sûr, 15.
          La fonction qui renvoie la longueur, len, tient son nom de length, nous la réécrivons sous la forme :
          def longueur (L):
          	nb = 0
          	for v in L:
          		nb = nb + 1
          	return nb
          print longueur([9,2,3])
          

          Il faut pouvoir créer un vecteur pour pouvoir travailler avec lui.
          def remplirt (n):
              i = 0
              T = []
              while (i <= n):
                  T.insert(i)
                  i = i + 1
              return T
          print remplirt(10)
          def somt (n,L):
              i = 0
              s = 0
              while i < n:
                 s = s + L[i]
                 i = i + 1
              return s
          print somt(6,remplirt(6))
          print somt(7,remplirt(7))
          

          Il vous reste à faire quelques exercices pour vous habituer à Python et aux listes. Voici une fonction qui permet de créer un vecteur de taille donnée (en argument) qui ne soit pas rangé :
          def creer (n):
              T = []
              T.append(1)
              T.append(1)
              i=2
              while (i <= n):
                 j=(T[i-1] + T[i-2])%27
                 T.append(j)
                 i = i + 1
              return T
          
          • Dans un vecteur non trié, renvoyer le plus grand élément.
          • Dans un vecteur non trié, renvoyer le plus petit élément.
          • Dans un vecteur non trié, renvoyer le second plus grand élément.
          • Dans un vecteur non trié, renvoyer le nombre d'éléments plus grands qu'un x donné.
          • Dans un vecteur non trié, remplcer chaque élément par son carré.
            def repcar (L):
                nb = long(L)
                i = 0
                while i < nb:
                    L[i] = L[i] * L[i]
                    i = i + 1
                return L
            print "repcar ([1,9,-5,3,2]) == ", repcar ([1,9,-5,3,2])
            #repcar ([1,9,-5,3,2]) ==  [1, 81, 25, 9, 4]
            
          • Concaténation, en vidant peu à peu la première liste dans la seconde. Vu en cours, à faire tourner.
          • Inversion avec pgdg, voir ci-dessous.
            NB La fonction vide répond vrai si la liste est vide, la fonction cdr renvoie la sous-liste formée de tous les éléments sauf le premier, la fonction car renvoie le premier élément, la fonction cons construit une liste avec d'abord son premier argument et ensuite tous les autres (un peu comme concat d'un singleton et d'une liste).
            (define (pgdg l)
              (if (vide l) l
            	(if (vide (cdr l)) l
            	  (if (vide (cddr l)) (inv2 l)
            		(cons (car (pgdg (cdr l)))
            			  (pgdg (cons (car l)
                					  (pgdg (cdr (pgdg (cdr l)))))))))))
            
            

          • Tri par insertion

            Faire une fonction d'insertion puis une fonction qui s'en sert pour trier le vecteur.
          • Quicksort

            Il s'agit de faire une fonction qui
            1. prend une valeur dans le vecteur, le pivot.
            2. fait un vecteur VINF de tous les éléments plus petits que le pivot dans le vecteur de départ.
            3. fait un vecteur VSUP de tous les éléments plus grands que le pivot dans le vecteur de départ.
            4. trie ces deux vecteurs, grâce à quicksort.
            5. concatène ces trois éléménts (les deux vecteurs triés et le pivot).

        5. Dessin

          Pour travailler avec la "tortue", il faut inclure des "bibliothèques" et, il n'y a plus qu'à.
          N'hésitez pas à regarder la documentation suivante.
          from turtle import *
          import time
          import math
          
          Par exemple pour ne pas afficher la tortue mais dessiner un triangle :
          def dessin3():
              ht()
              color("red","green") #choix de couleurs
              fd(100)  #avancer
              left(90) #tourner
              fd(100)
              left(135)
              fd(141)
              print("fini")
              time.sleep(2.5) #laisser l'affichage quelques secondes
          dessin3()
          
          1. Affichez un carré
          2. Remplissez un carré
            Pour cela, il faut, avant la forme, annoncer
            fill(True)
            et après la forme finir avec  :
            fill(False)
          3. Dessiner des crénaux, sur un mur.
          4. Dessiner un personnage simplifié.
          5. Dessiner un visage simplifié avec les expressions suivantes : triste, gai, riant, effrayé.
          6. Dessiner un chateau-fort.
      2. C
        1. Premières fonctions
          /* voici un exemple tres simple */
          
          /* D abord une fonction elementaire */
          
          int som (int n) {
            if (n < 1) {
          	return 0;
            }
            return som (n - 1);
          }
           
        2. main et printf
          main () {
            printf("som (5) == %d\n",som(5));
            printf("som (6) == %d\n",som(6));
            printf("som (7) == %d\n",som(7));
          }
           
        3. Compilation et exécution
          mu.ai.univ-paris8.fr: gcc exo1.c
          mu.ai.univ-paris8.fr: a.out
          som(5) == 15
          som(6) == 21
          som(7) == 28
          mu.ai.univ-paris8.fr:
           
          On peut mettre les mots clé #include<stdio.h> en début de fichier pour éviter quelques "warning" disgrâcieux mais sans conséquence.
          Parfois, à la place de taper "a.out" vous avez besoin de taper "./a.out".

          Faire en C toutes les fonctions vues précédemment.

        4. Vecteurs
          void remplirt (int tab [100], int nb) {
          /* void à la place de int pour signifier qu'il n'y a rien à renvoyer*/  
            int pred, ante, i;
          
            if (nb > 99)
          	return;
            pred = 13;
            ante = 8;
            tab [0] = 8;
            tab [1] = 13;
            i = 2;
            while ( i < nb) {
          	tab [i] = (ante + pred) % 23;
              /* % est le modulo, le reste de la division entière */
          	ante = pred;
          	pred = tab [i];
          	i = i + 1;
            }
          }
          main () {
            int nb, t [100];
          
            nb = 20;
            remplirt (t, nb);
            affichet (t, nb);
          }
          

          Vous pouvez maintenant compléter cette fonction main et faire les fonctions suivantes :
          • somme des éléments du vecteur
          • nombre d'éléments positifs d'un vecteur
          • nombre d'éléments impairs d'un vecteur
          • plus grand élément du vecteur
          • second plus grand élément du vecteur
          • troisième plus petit élément du vecteur
          • somme des éléments supérieurs à x (second argument)
          • créer le miroir du vecteur
          • nombre d'éléments supérieurs à un x donné
          • élément médian du vecteur (celui qui, à 1 près, a autant d'éléments supérieurs à lui que d'éléments inférieurs à lui)
          • en supposant un vecteur rangé dans l'ordre croissant, insérer un élément à sa place (et donc décaler les éléments plus grands).
          • Utiliser la dernière fonction, pour, un par un, insérer tous les éléments d'un vecteur dans un vecteur au préalable vide.

          Dans la suite, nous utilisons parfois le terme de "suite" pour désigner "tableau" ou "vecteur", le lecteur corrigera de lui-même.

          • Produit des carrés des n premiers entiers
          • Produit des cubes des n premiers entiers
          • Produit des puissances 4 des n premiers entiers
          • Produit de leur propre puissance des n premiers entiers

            0^0+1^1+2^2+3^3+...+n^n
          • Somme des puissances p des n premiers entiers
            0^p+1^p+2^p+3^p+...+n^p
          • Somme des puissances p des n premiers entiers
            0^n+1^n+2^n+3^n+...+n^n
          • Additions par additions et soustractions de 1.
          • Soustraction par additions et soustractions de 1.
          • nMultiplication entière par additions successives.
          • Division entière par soustractions successives.
          • Reste de la division entière par soustractions successives.
          • pgcd.
          • Fibonacci.
          • Somme des carrés des éléments d'une liste numérique
          • Plus grand élément d'une liste
          • Second plus grand élément d'une liste
          • Troisième plus petit élément d'une liste
          • Le nombre d'éléments négatifs d'une liste de nombres
          • Le nombre d'éléments positifs d'une liste de nombres
          • La somme des éléments de rang impairs (le premier, le troisième, le cinquième, ... dans l'ordre de la liste, pas par ordre décroissant ou autre). Exemple :
            * (somodd '(2 4 1 2 5 6 2))
            = 10
            
            1. Soit un tableau rangé (toutes les valeurs sont dans l'ordre croissant), faire une fonction d'un tel tableau, de son nombre d'éléments et d'un nombre x, la fonction renvoie l'emplacement auquel il faudrait insérer x pour que le tableau reste rangé.
              Par exemple dans le tableau [2, 7, 12, 19] la valeur 10 devrait être placée dans la case 2 (c'est-à-dire après le 7).
            2. Faire une fonction qui range une valeur dans un tableau rangé (en décalant toutes les valeurs à sa droite).
            3. Faire une fonction qui utilise la précédente pour ranger, élément après élément, toutes les valeurs d'un tableau.

            Cette procédure est nommée "tri par insertion".

            1. Prendre dans un tableau tous les éléments plus grands que l'autre paramètre de la fonction.
              lesgrands ([13, 7, 15, 2], 8) donne
              [13, 15]
              
            2. Prendre dans un tableau tous les éléments inférieurs ou égaux à l'autre paramètre de la fonction. (ce sont les autres !)
            3. Faites une fonction de tri basée sur la méthode suivante :
              • soit une liste l, son premier élément sera nommé "pivot" et le reste de la liste "sous-liste".
              • Fabriquer "petits" une liste de tous les éléments de la "sous-liste" inférieurs ou égaux au pivot.
              • Fabriquer "grands" une liste de tous les éléments de la "sous-liste" supérieurs au pivot.
              • Fabriquer "grandstries" la liste grands une fois triée.
              • Fabriquer "petitstries" la liste petits une fois triée.
              • Concaténer tout cela pour faire une liste ayant tous les éléments de l mais qui soit triée.
      3. Assembleurs voir le résultat de la compilation avec gcc -S de votre programme, on affichera ensuite le fichier ".s" généré.
        On trouvera sur le site Rostta des exemples bien faits de programmes dans différents (nombreux) lanages. Je donne ici quelques exemples, dont certains sont tirés de ce site.
      4. COBOL
      5. FORTRAN et BASIC
      6. Pascal et ADA
      7. Autres
    3. À objets ?
      Nous allons donner un exemple en Java.
      public class big {
      	public static void main(String[] args) {
      		
      		int i, som, fac, fi;
      		int n;
      		n = 10;
      		int tab[] = new int[100];
      		System.out.println(" ");
      		i = 1;
      		som = 0;
      		fac = 1;
      		while (i <= n) {
      			som = som + i;
      			fac = fac * i;
      			i = i + 1;
      		}
      		System.out.println(" som iteratif " + som + " recursif  " + somme(n));
      		System.out.println(" produit iteratif " + fac + " recursif  " + fact(n));
      		i = 0;
      		n = 10;
      		while (i <= n) {
      			System.out.println("fib  " + i + "  =>  " + fib (i));
      			i = i + 1;
      		}
      		i = 2;
      		tab[0] = 1;
      		tab[1] = 1;
      		while (i < n) {
      			tab[i] = tab[i - 1] + tab[i - 2];
      			i = i + 1;
      		}
      		i = n - 1;
      		while (i >= 0) {
      			System.out.println("tab  " + i + "  =>  " + tab [i]);
      			i = i - 1;
      		}
      		/* vecteurs dans d'autres fonctions*/
      		remplir(n, tab);
      		voir (n, tab);
      					
      	}
      	public static int somme (int n) {
      		if (n < 1)
      			return 0;
      		return n + somme (n - 1);
      	}
      	public static int fact (int n) {
      		if (n < 1) {
      			return 1;
      		}
      		else {
      			return n + fact (n - 1);
      		}
      	}
      	public static int fib (int n) {
      		if (n < 2)
      			return 1;
      		return fib (n - 1) + fib (n - 2);
      	}
      	public static void remplir (int nb, int [] vec) {
      		int i, j, tmp;
      		i = 0;
      		j = nb - 1;
      		tmp = 5;
      		while (i < nb) {
      			vec[i] = j;
      			j = j - tmp;
      			if (j < 0) {
      				tmp = - tmp;
      				tmp++;
      			}
      			if (j > 30) {
      				tmp = - tmp;
      				tmp--;
      			}
      			i = i + 1;
      		}
      	}
      	public static void voir (int nb, int [] vec) {
      		int i;
      		i = 0;
      		while (i < nb) {
      			System.out.println("vec ( "+i+" ) == " + vec[i]);
      			i++;
      		}
      	}
      }
      

      Nous mettons tout cela dans un fichier big.java. Il ne reste plus qu'à compiler puis exécuter pour vérifier que tout cela marche bien.
      $ javac big.java
      $ java big
      Il faut compter jusqu a : 10
      Somme recursive      => 3628800
      Somme vecteur      => 55
      Recursive terminale  => 55
      Produit recursif     => 3628800
      vec ( 0 ) == 9
      vec ( 1 ) == 4
      vec ( 2 ) == -1
      vec ( 3 ) == 3
      vec ( 4 ) == 7
      vec ( 5 ) == 11
      vec ( 6 ) == 15
      vec ( 7 ) == 19
      vec ( 8 ) == 23
      vec ( 9 ) == 27
      vec ( 0 ) == 27
      vec ( 1 ) == 23
      vec ( 2 ) == 19
      vec ( 3 ) == 15
      vec ( 4 ) == 11
      vec ( 5 ) == 7
      vec ( 6 ) == 3
      vec ( 7 ) == -1
      vec ( 8 ) == 4
      vec ( 9 ) == 9
      Fib 1 = 1
      Fib 2 = 2
      Fib 3 = 3
      Fib 4 = 5
      Fib 5 = 8
      Fib 6 = 13
      Fib 7 = 21
      Fib 8 = 34
      Fib 9 = 55
      Fib direct 10 = 89
      Fib recur  10 = 89
      $
      

  4. Fonctionnel
    Fonctionnel, est-ce pour parler des fonctions qu'on peut manipuler ou pour le mode dans lequel on ne change jamais la valeur d'une variable ?

  5. Logique
    Nous étudierons le langage PROLOG pour ses capacités à programmer des expressions logiques.
    1. Premières clauses

      Voici maintenant une primitive qui calcule le carré d'un nombre, et celle qui compte la somme des N premiers entiers :
      carre(N,C):- C is N * N.
      somme(0,0).
      somme(N,S):-   N1 is N - 1,
                     somme(N1,S1),
                     S is S1 + N.
      

      Nous les avons mises dans un fichier exo1.pl. Pour s'en servir avec prolog, dans le terminal il suffit de lancer prolog.
      $ swipl
      Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.2.3)
      Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
      SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
      and you are welcome to redistribute it under certain conditions.
      Please visit http://www.swi-prolog.org for details.
      
      For help, use ?- help(Topic). or ?- apropos(Word).
      
      ?- consult(exo).
      true.
      
      ?- carre(5,N).
      
      N = 25 
      
      Yes
      ?- carre(5,7).
      
      No
      
      ?- somme(3,Z).
      
      Z = 6
      
      Yes
      
      ?-
      

      Emacs et Prolog

      Pour que emacs respecte l'indentation prolog, il convient de rajouter deux lignes au fichier .emacs (qui se trouve dans votre répertoire "home").
      (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t)
      (add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode))
      
      on pourra par exemple, sous terminal taper les lignes suivantes en finissant par "contrôle-d" :

      JJBook : cat >> ~/.emacs
      (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t)
      (add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode))
      

      Il vous reste à faire un certain nombre de fonctions numériques (jusqu'à la suite de Fibonacci, par exemple).

    2. Hérédité
       pere(chuck, eddie).
       pere(chuck, elvis).
       pere(elvis,john).
       pere(elvis,mick).
       pere(john,janis).
       pere(john,nico).
       
      Ceci énonce une base de faits dans laquelle chuck est le père d'eddie... et ainsi de suite. On peut lancer prolog et poser des questions. Je mets tous ces faits dans le fichier rock.pl dont vous trouvez le contenu ci-dessous.
       $ swipl
       Welcome to SWI-Prolog (Version 3.3.4)
       Copyright (c) 1990-2000 University of Amsterdam. 
       Copy policy: GPL-2 (see www.gnu.org)
      
       For help, use ?- help(Topic). or ?- apropos(Word).
      
       1 ?- consult(rock).
       % rock compiled 0.01 sec, 9,868 bytes
      
       Yes
       2 ?- 
       pere(X,janis).
      
       X = john 
      
       Yes
       3 ?- pere(janis,X).
      
       No
       4 ?- 
       
      Développons la base de faits.
       /* famille du rock, due a J-J Bourdin */
       /* les pères                          */
       pere(chuck, eddie).
       pere(chuck, elvis).
       pere(elvis,john).
       pere(elvis,mick).
       pere(john,janis).
       pere(john,nico).
       pere(john,lou).
       pere(mick,pete).
       pere(mick,robert).
       pere(mick,david).
       pere(lou,vanessa).
       pere(lou,marianne).
       /* les mères                          */
       mere(ella,eddie).
       mere(ella,elvis).
       mere(edith,john).
       mere(edith,mick).
       mere(janis, sinead).
       mere(nico, joan).
      
       feminin(janis).
       feminin(nico).
       feminin(vanessa).
       feminin(marianne).
       feminin(sinead).
       feminin(joan).
      
       masculin(chuck).
       masculin(eddie).
       masculin(elvis).
       masculin(john).
       masculin(mick).
       masculin(lou).
       masculin(david).
       masculin(pete).
       masculin(robert).
      
       fils(X,Y):-pere(Y,X),masculin(X).
       fils(X,Y):-mere(Y,X),masculin(X).
       fille(X,Y):-pere(Y,X),feminin(X).
       fille(X,Y):-mere(Y,X),feminin(X).
      
       /*  quelques primitives généralistes */
       /*  admirez les variables            */
       parent(X,Y):-pere(X,Y).
       parent(X,Y):-mere(X,Y).
       enfant(X,Y):-parent(Y,X).
       gdparent(X,Y) :- parent(X,Z),parent(Z,Y).
      
       
      Note
      Pour tester l'égalité, on peut utiliser == c'est-à-dire :
       egal(A,B):-A==B.
       
      cela fonctionne :
       ?- egal(5,5).
      
       Yes
       ?- egal(4,5).
      
       No
       
      Par contre pour la différence, il faut écrire =\= pour les valeurs numériques (et pas les textes) :
       diffe(A,B):-A=\=B.
       
      Pour les autres cas, l'inverse d'une valeur logique est sa négation:
       egal(A,B):-A==B.
       different(A,B):-not(egal(A,B)).
       
      Il faut maintenant faire les prédicats :
      1. Cousin (puis cousine) au 3è degré.
      2. Cousin (puis cousine) au 4è degré.
      3. Cousin (puis cousine) au 5è degré.
      4. Cousin (puis cousine) au 6è degré.
      5. Degré de cousinage entre deux personnes.
      Il faut maintenant faire les prédicats :
      1. puissance en récursivité terminale,
      2. miroir en récursivité terminale,
    3. Listes en Prolog
      Une liste est soit la liste vide, soit la construction d'un élément et d'une liste. Par exemple [] ou [1, 7, 8, 3].

      Quand on veut utiliser une liste, on met un "pipe" entre le ou les permiers éléments et le reste de la liste.
      long([],0).
      long([A|As],L):-long(As,T),
                      L is T + 1.
      
      Nous avons vu aussi la somme des éléments (on n'ajoute pas 1 mais A). Vous pouvez faire
      • la somme des carrés des éléments de la liste,
      • la somme des cubes des éléments de la liste,
      • le plus grand des éléments de la liste,
      • le plus petit des éléments de la liste,
      • le second plus grand des éléments de la liste.
      Nous présentons maintenant la fonction concat qui fait de deux listes une troisième. concat([],Bs,Bs). concat([A|As],Bs,[A|Cs]):-concat(As,Bs,Cs).
      Faites donc maintenant les fonctions :
      • miroir,
      • insertion d'un élément dans une liste rangée,
      • tri par insertion,
      • quicksort.
  6. Divers
    1. LaTeX
    2. Partiel et LaTeX

      Vous trouverez un texte de partiel (de 2012), en cliquant ici. Il s'agit de la version pdf à afficher avec acroread.
      Le texte lui-même est donné en cliquant là. Il faut le compiler deux fois avec LaTeX puis l'afficher ou en faire un ps ou en faire un pdf.
      $ latex ilp10_p.tex
      ...
      
      $ latex ilp10_p.tex
      ...
      Overfull \hbox (5.3039pt too wide) in paragraph at lines 131--135
      []\T1/cmr/bx/n/10.95 SomCar : \T1/cmr/m/n/10.95 ?cri-vez une fonc-tion qui pren
      d
      [1]
      Overfull \hbox (7.47572pt too wide) in paragraph at lines 149--153
      \T1/cmr/m/n/10.95 en pa-ra-m?tre une liste et ren-voie la somme
      [2] (./ilp07_p.aux) )
      (see the transcript file for additional information)
      Output written on 12_ilp_p.dvi (8 pages, 7144 bytes).
      Transcript written on ilp10_p.log.
      
      Ensuite on le passe en ps ou en pdf, selon l'usage souhaité.
      $ dvips -o 12_ilp_p.ps 12_ilp_p.dvi
      . 
      
      [1] [2] 
      $ dvipdf 12_ilp_p.dvi
      $
      

      ou :
      white.home: dvipdf 12_ilp_p.dvi
      white.home: open 12_ilp_p.pdf
      white.home: 
      
      Maintenant le fichier .ps ou fichier .pdf et le fichier .dvi (on peut voir ce dernier grâce à xdvi).
      Un autre exemple, vous voyez tout de suite ce que fait le programme suivant n'est-ce pas ?.
      \documentclass{article}
      \pagestyle{empty}
      \usepackage{ifthen}
      
      \newcounter{mula}
      \newcounter{mulb}
      \newcounter{prod}
      \newcounter{compt}
      \newcounter{fv}
      \newcounter{fi}
      
      \newcommand{\mul}[2]{
         \setcounter{mula}{#1}
         \setcounter{mulb}{#2}
         \setcounter{prod}{0}
         \setcounter{compt}{0}
         \mulaux{#1}
      }
      
      \newcommand{\mulaux}[1]{
      
          \ifthenelse{#1 > \thecompt}{\mulo{#1}}{}
      }
      
      \newcommand{\mulo}[1]{
         \stepcounter{compt}
         \addtocounter{prod}{\themulb}
         \mulaux{#1}
      }
      \newcommand{\fac}[1]{
         \setcounter{fv}{1}
         \setcounter{fi}{1}
         \facaux{#1}
         La factorielle de #1 est \thefv ~\\~\\
      }
      \newcommand{\facaux}[1]{
         \ifthenelse{#1 > \thefi}{\faco{#1}}{}
      }
      \newcommand{\faco}[1]{
         \stepcounter{fi}
         \mul{\thefi}{\thefv}
         \setcounter{fv}{\theprod}
         \facaux{#1}
      }
      
      \begin{document}
      
      \underline{\Huge\bf I.L.I. LaTeX}\\~\\
      on affiche pour 3 et 5 \\~\\
      \fac{3}
      \fac{5}
      \end{document}
      

      le mettre dans un fichier, le compiler et regarder est une bonne méthode...

      Enfin, un rapport

      Voici, ici un exemple de rapport écrit en LaTeX. Le fichier de bibliographie (si vous en avez besoin) est donné de même que le résultat de la compilation de l'ensemble vers un fichier pdf: projet.pdf .
  • Shell

    1. Principes
      Rajoutez le répertoire courant dans votre chemin d'accès (PATH) par exemple, dans le fichier .bashrc vous pouvez rajouter la ligne:
      	  PATH=$PATH'./:'
      	
      Premier programme
       #!/bin/sh
       #  affiche les arguments
      
         echo $1
         echo $2
         echo $3
         echo $4
      
       
      Utilisons-le :

      Vous mettez ce code dans un fichier, par exemple de nom voir.sh.

      Vous rendez ce fichier exécutable, par exemple par :

       $chmod 755 voir.sh
       
    2. NB. Si vous voulez vérifier, vous trouvez que le fichier est exécutable.

      Il en ira de même à chaque nouveau shellscript : il doit être exécutable et on doit y avoir accès pour pouvoir l'exécuter.

       $ voir.sh Je fais souvent ce reve etrange
       Je
       fais
       souvent
       ce
       $
       
       #!/bin/sh
       #  affiche les arguments
      
         echo $1
         shift
         echo $1
         shift
         echo $1
         shift
         echo $1
         shift
      
      
       
      Utilisons-le :
       $ voir.sh Je fais souvent ce reve etrange
       Je
       fais
       souvent
       ce
       $
       
      Continuons avec le double d'un nombre :
       if test $# -eq 1
       then
         expr $1 + $1
       else
         echo "usage: $0 n"
       fi
       
      Je mets ceci dans un fichier carre.sh et cela donne à l'usage :
       otake: chmod +x carre.sh 
       otake: carre.sh 5
       10
       otake: carre.sh 6
       12
       
    3. Structures de Contrôle
      1. if

        Comme à notre habitude, nous verrons la fonction somme.
        Fichier som.sh

        #!/bin/sh
        
        #juste la somme
        
        if test $# -lt 1
        then
          echo "usage: $0 nb"
        else
          if test $1 -le 0
          then
            echo 0
          else
            n=`expr $1 - 1`
            f=`som.sh $n`
            expr $f + $1
          fi
        fi
         #jj@aqua$ chmod +x som.sh 
         #jj@aqua$ som.sh 5
         #15
         
        Notez que j'ai modifié mon fichier .bashrc en ajoutant la ligne suivante :
        PATH=$PATH'~/bin/:./:'
         
        pour y rajouter mon répertoire bin (où je mets mes exécutables) et le répertoire courant.
        Pour que ceci soit effectif il faut lancer la commande shell :
           source ~/.bashrc
         

        Fibonacci récursif

        Ce script est dans un fichier fibr.sh dans un répertoire qui fait partie de mon PATH.
        #!/bin/sh
        if test $# -ne 1
        then echo "usage: $0 nb"
        else
            case $1 in
                0) echo 1;;
                1) echo 1;;
                *)
                    s=`expr $1 - 1`
                    t=`expr $1 - 2`
                    u=`fibr.sh $s`
                    v=`fibr.sh $t`
                    expr $u + $v;;
            esac
        fi
        
        Donc il faut refaire maintenant tous les exercices numériques en shell.
        • Multiplication par additions successives.
        • Somme des cubes.
        • A puissance B.
        • Reste de la division entière.
        • pgcd.
        • Fibonacci.
        • Plus grand de deux valeurs.
        • Plus grand de trois valeurs.
        • Plus grand de quatre valeurs.
        • Plus grand de cinq valeurs.
        • Second plus petit de cinq valeurs.
          • Pour afficher les paramètres, nous avons fait plusieurs essais. mais on est limité quant au nombre de paramètres. Ce qui n'est pas le cas avec le programme suivant :
            #!/bin/bash
            n=$#
            i=1
            while test $i -lt $n
            do
              echo $1
              shift
              i=`expr $i + 1`
            done
            
            ou une version plus simple, puisque shift modifie également le nombre d'arguments.

            #!/bin/bash
            while test $# -gt 0
            do
            	echo $1
            	shift
            done
            
          • case
            Voyons le case sur un exemple sans ambition :
            jj@sunfire$ cat essai.sh
            case $# in
              1) echo $1;;
              2) echo $1 $2;;
              3) echo $1 $2 $3;;
              *) echo "trop de parametres"
              esac
            jj@sunfire$ essai.sh 1 2
            1
            2
             
          • while

            Fichier faciter.sh

             #!/bin/sh
            
             if test $# -eq 1
             then
                n=$1
                f=1
                while test $n -ge 1
                do
                   f=`expr $f \* $n`
                   n=`expr $n - 1`
                done
                echo $f
             else
            	echo "un argument, un !"
             fi
            
             #jj@aqua$ chmod 755 faciter.sh 
             #jj@aqua$ faciter.sh 6
             #720
             
            Refaites tous les exercices numériques en shell itératif.
            • Multiplication par additions successives.
            • Somme des cubes.
            • A puissance B.
            • Reste de la division entière.
            • pgcd.
            • Fibonacci.
            • Produit des puissances n.
              • Les for

                D'abord prendre et afficher tous les arguments :
                Fichier louque.sh
                 for i
                 do
                   echo $i
                 done
                 
                Ensuite prendre et afficher "tous" les fichiers du répertoire courant :
                Fichier ici.sh
                 for i in *
                 do
                   echo $i
                 done
                 
                Enfin, prendre chacun des termes :
                Fichier tiens.sh
                 f=1
                 for i in 1 2 3 4 5 6
                 do
                   f=`expr $f \* $i`
                   echo $i $f
                 done
                 


      Dernière mise à jour de ce document :

      23/7/2020