diff --git a/slides/.gitignore b/slides/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5d70ba61d5fe42f55b454f3b8f53c7b688060a3d --- /dev/null +++ b/slides/.gitignore @@ -0,0 +1,3 @@ +*.pdf +mermaid-filter.err +.puppeteer.json diff --git a/slides/Makefile b/slides/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b3411621983decb133ccb5a3c87353d872768405 --- /dev/null +++ b/slides/Makefile @@ -0,0 +1,61 @@ +PDFOPTIONS = -t beamer +# PDFOPTIONS += -F pantable +PDFOPTIONS += -F mermaid-filter +PDFOPTIONS += --highlight-style my_highlight.theme +PDFOPTIONS += --pdf-engine xelatex +PDFOPTIONS += -V theme:metropolis +PDFOPTIONS += -V themeoptions:numbering=none -V themeoptions:progressbar=foot +PDFOPTIONS += -V fontsize=smaller +PDFOPTIONS += -V urlcolor=blue + +MD=$(wildcard *.md) # Tous les fichiers .md +PDF=$(MD:%.md=%.pdf) # Pour les fichier pdf on transforme .md -> .pdf +HTML=$(MD:%.md=%.html) # Pour les fichier html on transforme .md -> .html +MARKDOWN=$(MD:%.md=%.markdown) # Pour les fichier markdown on transforme .md -> .markdown +CHROMIUM:=$(shell which chromium || which chromium-browser) + +all: puppeteer $(PDF) +# all: puppeteer $(PDF) $(HTML) # La cible par défaut (all) exécute les cibles %.pdf + +docker: docker-compose.yml + docker compose run slides + +docker_clean: docker-compose.yml + docker compose run slides clean + +puppeteer: + @echo "Setting chromium to $(CHROMIUM) for puppeteer" + @echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json + +index.md: gen_index.sh + $(shell ./gen_index.sh) + +index.html: index.md + pandoc -s $(OPTIONS) --css ../css/tufte-css/tufte.css -o $@ $^ + +markdown: $(MARKDOWN) # La markdown les cibles %.markdown + +%.pdf: %.md metadata.yaml # %.pdf (chaque fichier %.md génère un fichier avec le même nom mais l'extension .pdf et la dépendance metadata.yaml) + pandoc -s $(OPTIONS) $(PDFOPTIONS) -o $@ $^ + +%.markdown: %.md metadata.yaml yq + sed '1 { /^---/ { :a N; /\n---/! ba; d} }' $< > no_header + grep -v -F -x -f no_header $< > header.yaml + echo "---" > tmp.yaml + ./yq_linux_amd64 merge metadata.yaml header.yaml >> tmp.yaml + cat tmp.yaml no_header > $@ + rm no_header header.yaml tmp.yaml + +yq: # On peut même télécharger un petit programme avec notre makefile + wget -nc https://github.com/mikefarah/yq/releases/download/3.4.1/yq_linux_amd64 + chmod "u+x" yq_linux_amd64 + +deploy: all index.html + mkdir -p algo_cours + cp *.pdf algo_cours + cp index.html algo_cours + +clean: + rm -rf *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json algo_cours *.err + +.PHONY: clean index.md puppeteer yq diff --git a/slides/cours_1.md b/slides/cours_1.md new file mode 100644 index 0000000000000000000000000000000000000000..7ff00f2dd69b007dcc9a9b6b1d332045304b06b0 --- /dev/null +++ b/slides/cours_1.md @@ -0,0 +1,349 @@ +--- +title: "Introduction aux algorithmes" +date: "2024-09-16" +--- + +# Qu'est-ce qu'un algorithme? + +## Définition informelle (recette) + +* des entrées (les ingrédients, le matériel utilisé) ; +* des instructions élémentaires simples (frire, flamber, etc.), dont les + exécutions dans un ordre précis amènent au résultat voulu ; +* un résultat : le plat préparé. + +. . . + +## Histoire et étymologie + +- Existent depuis 4500 ans au moins (algorithme de division, crible + d'Eratosthène). +- Le mot algorithme est dérivé du nom du mathématicien perse + *Muḥammad ibn Musā al-Khwārizmī*, qui a été "latinisé" comme + *Algoritmi*. + +. . . + +## Définition formelle + +En partant d'un état initial et d'entrées (peut-être vides), une séquence finie +d'instruction bien définies (ordonnées) implémentables sur un ordinateur, afin +de résoudre typiquement une classe de problèmes ou effectuer un calcul. + +# Notions de base d'algorithmique + +## Variable + +. . . + +* Paire: identifiant - valeur (assignation); + +## Séquence d'instructions / expressions + +. . . + +* Opérateurs (arithmétiques / booléens) +* Boucles; +* Structures de contrôle; +* Fonctions; + + +# Algorithme de vérification qu'un nombre est premier (1/3) + +Nombre premier: nombre possédant deux diviseurs entiers distincts. + +. . . + +## Algorithme naïf (problème) + +```C +booléen est_premier(nombre) + si + pour tout i, t.q. 1 < i < nombre + i ne divise pas nombre + alors vrai + sinon faux +``` + +. . . + +## Pas vraiment un algorithme: pas une séquence ordonnée et bien définie + +. . . + +## Problème: Comment écrire ça sous une forme algorithmique? + +# Algorithme de vérification qu'un nombre est premier (2/3) + +## Algorithme naïf (une solution) + +```C +booléen est_premier(nombre) // fonction + soit i = 2 // variable, type, assignation + tant que i < nombre // boucle + si nombre modulo i == 0 // expression typée + retourne faux // expression typée + i = i + 1 + retourne vrai // expression typée +``` + +# Algorithme de vérification qu'un nombre est premier (3/3) + +## Algorithme naïf (une solution en C) + +```C +bool est_premier(int nombre) { + int i; // i est un entier + i = 2; // assignation i à 2 + while (i < nombre) { // boucle avec condition + if (0 == nombre % i) { // is i divise nombre + return false; // i n'est pas premier + } + i = i + 1; // sinon on incrémente i + } + return true; +} +``` + +. . . + +## Exercice: Comment faire plus rapide? + +# Génération d'un exécutable + +- Pour pouvoir être exécuté un code C doit être d'abord compilé (avec `gcc` ou `clang`). +- Pour un code `prog.c` la compilation "minimale" est + + ```bash + $ gcc prog.c + $ ./a.out # exécutable par défaut + ``` + +- Il existe une multitude d'options de compilation: + + ```console + $ gcc -O1 -std=c11 -Wall -Wextra -g prog.c -o prog + -fsanitize=address + ``` + 1. `-std=c11` utilisation de C11. + 2. `-Wall et -Wextra` activation des warnings. + 3. `-fsanitize=…` contrôles d’erreurs à l’exécution (coût en performance). + 4. `-g` symboles de débogages sont gardés. + 5. `-o` défini le fichier exécutable à produire en sortie. + 6. `-O1`, `-O2`, `-O3`: activation de divers degrés d'optimisation + + + +# La simplicité de C? + +## 32 mots-clé et c'est tout + +---------------- -------------- ---------------- --------------- +`auto`{.C} `double`{.C} `int`{.C} `struct`{.C} +`break`{.C} `else`{.C} `long`{.C} `switch`{.C} +`case`{.C} `enum`{.C} `register`{.C} `typedef`{.C} +`char`{.C} `extern`{.C} `return`{.C} `union`{.C} +`const`{.C} `float`{.C} `short`{.C} `unsigned`{.C} +`continue`{.C} `for`{.C} `signed`{.C} `void`{.C} +`default`{.C} `goto`{.C} `sizeof`{.C} `volatile`{.C} +`do`{.C} `if`{.C} `static`{.C} `while`{.C} +---------------- -------------- ---------------- --------------- + +# Déclaration et typage + +En C lorsqu'on veut utiliser une variable (ou une constante), on doit déclarer son type + +```C +const double two = 2.0; // déclaration et init. +int x; // déclaration (instruction) +char c; // déclaration (instruction) +x = 1; // affectation (expression) +c = 'a'; // affectation (expression) +int y = x; // déclaration et initialisation en même temps +int a, b, c; // déclarations multiples +a = b = c = 1; // init. multiples +``` + +# Les variables (1/2) + +## Variables et portée + +- Une variable est un identifiant, qui peut être liée à une valeur (un expression). +- Une variable a une **portée** qui définit où elle est *visible* (où elle peut être accédée). +- La portée est **globale** ou **locale**. +- Une variable est **globale** est accessible à tout endroit d'un programme et doit être déclarée en dehors de toute fonction. +- Une variable est **locale** lorsqu'elle est déclarée dans un **bloc**, `{...}`{.C}. +- Une variable est dans la portée **après** avoir été déclarée. + +# Les variables (2/2) + +## Exemple + +```C +float max; // variable globale accessible partout +int foo() { + // max est visible ici + float a = max; // valide + // par contre les varibles du main() ne sont pas visibles +} +int main() { + // max est visible ici + int x = 1; // x est locale à main + { + // x est visible ici, y pas encore + // on peut par exemple pas faire x = y; + int y = 2; + } // y est détruite à la sortie du bloc +} // x est à la sortie de main + +``` + +<!-- TODO: quiz, compile, compile pas --> +<!-- ```C +int main() { + global = 1; +} // COMPILE PAS +``` + +```C +int main() { + int global = 1; + { + printf("global = %d", global); + } +} // COMPILE +``` + +```C +int local; + +int main() { + local = 1; + { + printf("local = %d", local); + } +} // COMPILE +``` + +```C +#include <stdio.h> +int local = 0; + +int main() { + int local = -1; + { + int local = 1; + printf("local = %d\n", local); + } +} // COMPILE +``` --> + +# Quiz: compile ou compile pas? + +## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501934) + +# Types de base (1/4) + +## Numériques + +Type Signification (**gcc pour x86-64**) +---------------------------------- --------------------------------------------- +`char`{.C}, `unsigned char`{.C} Entier signé/non-signé 8-bit +`short`{.C}, `unsigned short`{.C} Entier signé/non-signé 16-bit +`int`{.C}, `unsigned int`{.C} Entier signé/non-signé 32-bit +`long`{.C}, `unsigned long`{.C} Entier signé/non-signé 64-bit +`float`{.C} Nombre à virgule flottante, simple précision +`double`{.C} Nombre à virgule flottante, double précision +---------------------------------- --------------------------------------------- + +**La signification de `short`{.C}, `int`{.C}, ... dépend du compilateur et de l'architecture.** + +# Types de base (2/4) + +Voir `<stdint.h>` pour des représentations **portables** + +Type Signification +---------------------------------- --------------------------------------------- +`int8_t`{.C}, `uint8_t`{.C} Entier signé/non-signé 8-bit +`int16_t`{.C}, `uint16_t`{.C} Entier signé/non-signé 16-bit +`int32_t`{.C}, `uint32_t`{.C} Entier signé/non-signé 32-bit +`int64_t`{.C}, `uint64_t`{.C} Entier signé/non-signé 64-bit +---------------------------------- --------------------------------------------- + +. . . + +## Prenez l'habitude d'utiliser ces types-là! + +# Types de base (3/4) + +## Booléens + +- Le ANSI C n'offre pas de booléens. +- L'entier `0`{.C} signifie *faux*, tout le reste *vrai*. +- Depuis C99, la librairie `stdbool` met à disposition un type `bool`{.C}. +- En réalité c'est un entier: + - $1 \Rightarrow$ `true`{.C} + - $0 \Rightarrow$ `false`{.C} +- On peut les manipuler comme des entier (les sommer, les multiplier, ...). + +# Quiz: booléens + +## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501922) + +<!-- TODO Quiz en ligne --> +<!-- ```C +if (42) { /* vrai */ } + +int x = 100; +if (x == 4) { /* faux */ } +if (x) { /* vrai */ } + +int x = 100; +while (x−−) { /* répète tant que x est différent de 0 */ } + +if (0) { /* faux */ } +if (i = 4) { /* vrai */ } +if (i = 0) { /* faux */ } + +#include <stdbool.h> + +bool x = true; +if (x) { /* vrai */ } +``` --> + +# Types de base (4/4) + +## Conversions + +- Les conversions se font de manière: + - Explicite: + ```C + int a = (int)2.8; + double b = (double)a; + int c = (int)(2.8+0.5); + ``` + - Implicite: + ```C + int a = 2.8; // warning, si activés, avec clang + double b = a + 0.5; + char c = b; // pas de warning... + int d = 'c'; + ``` + +# Quiz: conversions + +## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501925) + +<!-- TODO Quiz en ligne --> +<!-- ```C +int a = (int)2.8; // 2 + +double b = 2.85; +int c = b + 0.5; // 3 + +int d = a + 0.5; // 2 + +bool d = 2.78; // 1 +bool e = 1.0; // 1 +``` --> + diff --git a/slides/docker-compose.yml b/slides/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..57a6d7b3025ba7379c862fc0d18656055efdd270 --- /dev/null +++ b/slides/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3.3" +services: + slides: + image: omalaspinas/pandoc:latest + user: 1000:1000 + container_name: slides + volumes: + - ./:/data + entrypoint: ["make"] + working_dir: /data diff --git a/slides/figs/matrix_qr.png b/slides/figs/matrix_qr.png new file mode 100644 index 0000000000000000000000000000000000000000..ce2c45261290e5dc508c661a2c66b3545776e553 Binary files /dev/null and b/slides/figs/matrix_qr.png differ diff --git a/slides/gen_index.sh b/slides/gen_index.sh new file mode 100755 index 0000000000000000000000000000000000000000..9a1a026f1be11edac606857e902cd670652ca589 --- /dev/null +++ b/slides/gen_index.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -e + +function get_info() { + local field=$(echo "$fullName" | sed "$2q;d" $1); + IFS=$3; + local field=($field); + if [ "${field}" != $5 ]; then + return 1 + fi + local field=${field[1]}; + IFS=$4; + local field=($field); + local field=${field[1]}; + echo "$field" +} + +function fail() { + printf '%s\n' "$1" >&2 ## Send message to stderr. + exit "${2-1}" ## Return a code specified by $2, or 1 by default. +} + +OIFS=$IFS +NUM_LINE=2 +PREFIX="" +# PREFIX=cours/algo/slides/ + +classes=() +for i in *.md; do + [ -f "$i" ] || break + date="$(get_info $i 3 ":" '"' "date")" + if [ "$date" == 1 ]; then + fail "Error date field not found" + fi + comp="$(get_info $i 2 ":" '"' "title")" + if [ "$comp" == 1 ]; then + fail "Error title field not found" + fi + i="${i%.*}" + class="[${date}: ${comp}](${PREFIX}${i}.pdf)" + classes+=("$class") +done +IFS=$'\n' +classes=($(sort <<<"${classes[*]}")) +date=$(date '+%Y-%m-%d') +echo "---" >> index.md +echo "title: \"Slides du cours d'algorithmique\"" >> index.md +echo "date: \"${date}\"" >> index.md +echo "---" >> index.md +echo "" >> index.md +echo "# Tous les slides du cours d'algorithmique" >> index.md +echo "" >> index.md +for i in ${classes[*]}; do + echo "* $i" >> index.md +done + + +IFS=$OIFS diff --git a/slides/intro.md b/slides/intro.md new file mode 100644 index 0000000000000000000000000000000000000000..bda2274fcd234ce0a1b801c7fa35adb26adbf58e --- /dev/null +++ b/slides/intro.md @@ -0,0 +1,52 @@ +--- +title: "Introduction générale" +date: "2024-09-16" +--- + +# La hotline + +Nom Mél Bureau +-------------------- ------------------------------ -------------------- +Paul Albuquerque paul.albuquerque@hesge.ch B410 +Orestis Malaspinas orestis.malaspinas@hesge.ch A401 +-------------------- ------------------------------ -------------------- + +- Utilisez le libre service (l'horaire sera fixé prochainement). +- On va intensivement utiliser *Element*, installez le et utilisez le! +- Espace de discussion Matrix: <https://rb.gy/ku5es>, installez [element.io](https://element.io). + + {width=20%} + +# Cyberlearn + +Tout le contenu de ce qu'on raconte se trouve sur cyberlearn: + +- Algorithmes et structures de données + - <https://cyberlearn.hes-so.ch/course/view.php?id=7276> + - Clé d'inscription: algo_2023_24 + +- Programmation Sequentielle en C + - <https://cyberlearn.hes-so.ch/course/view.php?id=7282> + - Clé d'inscription: prog_seq_2023_24 + + +# Organisation du module + +## Cinq cours, 20% chacun. + +1. Algorithmes et structures de données (2 semestres): + * 1er semestre: + * bases de programmation en C jusqu'à Noël. + * algorithmique jusqu'à fin janvier. + * 2e semestre: + * algorithmique. + * Deux évaluations écrites par semestre (1er: novembre et janvier). +2. Programmation séquentielle en C (2 semestres) + * Familiarisation avec l'environnement Linux. + * Travaux pratiques en C. + * Apprentissage du gestionnaire de versions: git. + * Plusieurs exercices illustrant les concepts d'algorithmique. + * Évaluations (4 tests machine). +3. Programmation système + + diff --git a/slides/metadata.yaml b/slides/metadata.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fc66607d25b546ad0c748a706de2c4bde35f03ae --- /dev/null +++ b/slides/metadata.yaml @@ -0,0 +1,9 @@ +--- +subtitle: "Algorithmique et structures de données, 2024-2025" +author: "P. Albuquerque (B410) et O. Malaspinas (A401), ISC, HEPIA" +institute: En partie inspirés des supports de cours de P. Albuquerque +lang: fr-CH +revealjs-url: /reveal.js +mathjaxurl: "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML" +--- + diff --git a/slides/my_highlight.theme b/slides/my_highlight.theme new file mode 100644 index 0000000000000000000000000000000000000000..1d80b47b144ca30f252d27a32e3d3775267c7bbb --- /dev/null +++ b/slides/my_highlight.theme @@ -0,0 +1,204 @@ +{ + "text-color": null, + "background-color": "#f0f0f0", + "line-number-color": "#aaaaaa", + "line-number-background-color": null, + "text-styles": { + "Other": { + "text-color": "#8f5902", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Attribute": { + "text-color": "#c4a000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "SpecialString": { + "text-color": "#4e9a06", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Annotation": { + "text-color": "#8f5902", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Function": { + "text-color": "#000000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "String": { + "text-color": "#4e9a06", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "ControlFlow": { + "text-color": "#204a87", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Operator": { + "text-color": "#ce5c00", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "Error": { + "text-color": "#a40000", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + }, + "BaseN": { + "text-color": "#0000cf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Alert": { + "text-color": "#ef2929", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Variable": { + "text-color": "#000000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Extension": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Preprocessor": { + "text-color": "#8f5902", + "background-color": null, + "bold": false, + "italic": true, + "underline": false + }, + "Information": { + "text-color": "#8f5902", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "VerbatimString": { + "text-color": "#4e9a06", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Warning": { + "text-color": "#8f5902", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Documentation": { + "text-color": "#8f5902", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Import": { + "text-color": null, + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Char": { + "text-color": "#4e9a06", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "DataType": { + "text-color": "#204a87", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Float": { + "text-color": "#0000cf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Comment": { + "text-color": "#8f5902", + "background-color": null, + "bold": false, + "italic": true, + "underline": false + }, + "CommentVar": { + "text-color": "#8f5902", + "background-color": null, + "bold": true, + "italic": true, + "underline": false + }, + "Constant": { + "text-color": "#000000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "SpecialChar": { + "text-color": "#000000", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "DecVal": { + "text-color": "#0000cf", + "background-color": null, + "bold": false, + "italic": false, + "underline": false + }, + "Keyword": { + "text-color": "#204a87", + "background-color": null, + "bold": true, + "italic": false, + "underline": false + } + } +}