Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
1 result

Target

Select target project
No results found
Select Git revision
  • master
1 result
Show changes
1000 files
+ 181245
480
Compare changes
  • Side-by-side
  • Inline

Files

+5 −0
Original line number Diff line number Diff line
*.o
*.xopp*
slides/package-lock.json
slides/package.json
slides/.vscode/settings.json
.vscode/settings.json
slides/node_modules/.package-lock.json

README.md

0 → 100644
+17 −0
Original line number Diff line number Diff line
# Remerciements et contributions

Merci aux contributeurs suivants pour leurs efforts (dans un ordre alphabétique):

* P. Albuquerque
* J. Bach
* A. Boyer
* M. Corboz
* M. Divià
* Y. El Hakouni
* A. Escribano
* P. Kunzli
* G. Legouic
* G. Marino Jarrin
* H. Radhwan
* I. Saroukhanian
* C. Volta
+470 −0
Original line number Diff line number Diff line
@charset "UTF-8";

/* Import ET Book styles
   adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot");
    src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot");
    src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot");
    src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg");
    font-weight: bold;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "et-book-roman-old-style";
    src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot");
    src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

/* Tufte CSS styles */
html {
    font-size: 15px;
}

body {
    width: 87.5%;
    margin-left: auto;
    margin-right: auto;
    padding-left: 12.5%;
    font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
    background-color: #fffff8;
    color: #111;
    max-width: 1400px;
    counter-reset: sidenote-counter;
}

h1 {
    font-weight: 400;
    margin-top: 4rem;
    margin-bottom: 1.5rem;
    font-size: 3.2rem;
    line-height: 1;
}

h2 {
    font-style: italic;
    font-weight: 400;
    margin-top: 2.1rem;
    margin-bottom: 1.4rem;
    font-size: 2.2rem;
    line-height: 1;
}

h3 {
    font-style: italic;
    font-weight: 400;
    font-size: 1.7rem;
    margin-top: 2rem;
    margin-bottom: 1.4rem;
    line-height: 1;
}

hr {
    display: block;
    height: 1px;
    width: 55%;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;
}

p.subtitle {
    font-style: italic;
    margin-top: 1rem;
    margin-bottom: 1rem;
    font-size: 1.8rem;
    display: block;
    line-height: 1;
}

.numeral {
    font-family: et-book-roman-old-style;
}

.danger {
    color: red;
}

article {
    padding: 5rem 0rem;
}

section {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

p,
dl,
ol,
ul {
    font-size: 1.4rem;
    line-height: 2rem;
}

p {
    margin-top: 1.4rem;
    margin-bottom: 1.4rem;
    padding-right: 0;
    vertical-align: baseline;
}

/* Chapter Epigraphs */
div.epigraph {
    margin: 5em 0;
}

div.epigraph > blockquote {
    margin-top: 3em;
    margin-bottom: 3em;
}

div.epigraph > blockquote,
div.epigraph > blockquote > p {
    font-style: italic;
}

div.epigraph > blockquote > footer {
    font-style: normal;
}

div.epigraph > blockquote > footer > cite {
    font-style: italic;
}
/* end chapter epigraphs styles */

blockquote {
    font-size: 1.4rem;
}

blockquote p {
    width: 55%;
    margin-right: 40px;
}

blockquote footer {
    width: 55%;
    font-size: 1.1rem;
    text-align: right;
}

section > p,
section > footer,
section > table {
    width: 55%;
}

/* 50 + 5 == 55, to be the same width as paragraph */
section > dl,
section > ol,
section > ul {
    width: 50%;
    -webkit-padding-start: 5%;
}

dt:not(:first-child),
li:not(:first-child) {
    margin-top: 0.25rem;
}

figure {
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
    max-width: 55%;
    -webkit-margin-start: 0;
    -webkit-margin-end: 0;
    margin: 0 0 3em 0;
}

figcaption {
    float: right;
    clear: right;
    margin-top: 0;
    margin-bottom: 0;
    font-size: 1.1rem;
    line-height: 1.6;
    vertical-align: baseline;
    position: relative;
    max-width: 40%;
}

figure.fullwidth figcaption {
    margin-right: 24%;
}

/* Links: replicate underline that clears descenders */
a:link,
a:visited {
    color: inherit;
}

.no-tufte-underline:link {
    background: unset;
    text-shadow: unset;
}

a:link, .tufte-underline, .hover-tufte-underline:hover {
    text-decoration: none;
    background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(currentColor, currentColor);
    background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(currentColor, currentColor);
    -webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    -moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    background-repeat: no-repeat, no-repeat, repeat-x;
    text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8;
    background-position: 0% 93%, 100% 93%, 0% 93%;
}

@media screen and (-webkit-min-device-pixel-ratio: 0) {
    a:link, .tufte-underline, .hover-tufte-underline:hover {
        background-position-y: 87%, 87%, 87%;
    }
}

a:link::selection,
a:link::-moz-selection {
    text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe;
    background: #b4d5fe;
}

/* Sidenotes, margin notes, figures, captions */
img {
    max-width: 100%;
}

.sidenote,
.marginnote {
    float: right;
    clear: right;
    margin-right: -60%;
    width: 50%;
    margin-top: 0.3rem;
    margin-bottom: 0;
    font-size: 1.1rem;
    line-height: 1.3;
    vertical-align: baseline;
    position: relative;
}

.sidenote-number {
    counter-increment: sidenote-counter;
}

.sidenote-number:after,
.sidenote:before {
    font-family: et-book-roman-old-style;
    position: relative;
    vertical-align: baseline;
}

.sidenote-number:after {
    content: counter(sidenote-counter);
    font-size: 1rem;
    top: -0.5rem;
    left: 0.1rem;
}

.sidenote:before {
    content: counter(sidenote-counter) " ";
    font-size: 1rem;
    top: -0.5rem;
}

blockquote .sidenote,
blockquote .marginnote {
    margin-right: -82%;
    min-width: 59%;
    text-align: left;
}

div.fullwidth,
table.fullwidth {
    width: 100%;
}

div.table-wrapper {
    overflow-x: auto;
    font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif;
}

.sans {
    font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
    letter-spacing: .03em;
}

code, pre > code {
    font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
    font-size: 1.0rem;
    line-height: 1.42;
    -webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. See https://github.com/edwardtufte/tufte-css/issues/81#issuecomment-261953409 */
}

.sans > code {
    font-size: 1.2rem;
}

h1 > code,
h2 > code,
h3 > code {
    font-size: 0.80em;
}

.marginnote > code,
.sidenote > code {
    font-size: 1rem;
}

pre > code {
    font-size: 0.9rem;
    width: 52.5%;
    margin-left: 2.5%;
    overflow-x: auto;
    display: block;
}

pre.fullwidth > code {
    width: 90%;
}

.fullwidth {
    max-width: 90%;
    clear:both;
}

span.newthought {
    font-variant: small-caps;
    font-size: 1.2em;
}

input.margin-toggle {
    display: none;
}

label.sidenote-number {
    display: inline;
}

label.margin-toggle:not(.sidenote-number) {
    display: none;
}

.iframe-wrapper {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    padding-top: 25px;
    height: 0;
}

.iframe-wrapper iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

@media (max-width: 760px) {
    body {
        width: 84%;
        padding-left: 8%;
        padding-right: 8%;
    }

    hr,
    section > p,
    section > footer,
    section > table {
        width: 100%;
    }

    pre > code {
        width: 97%;
    }

    section > dl,
    section > ol,
    section > ul {
        width: 90%;
    }

    figure {
        max-width: 90%;
    }

    figcaption,
    figure.fullwidth figcaption {
        margin-right: 0%;
        max-width: none;
    }

    blockquote {
        margin-left: 1.5em;
        margin-right: 0em;
    }

    blockquote p,
    blockquote footer {
        width: 100%;
    }

    label.margin-toggle:not(.sidenote-number) {
        display: inline;
    }

    .sidenote,
    .marginnote {
        display: none;
    }

    .margin-toggle:checked + .sidenote,
    .margin-toggle:checked + .marginnote {
        display: block;
        float: left;
        left: 1rem;
        clear: both;
        width: 95%;
        margin: 1rem 2.5%;
        vertical-align: baseline;
        position: relative;
    }

    label {
        cursor: pointer;
    }

    div.table-wrapper,
    table {
        width: 85%;
    }

    img {
        width: 100%;
    }
}
Original line number Diff line number Diff line
*.pdf
*.json
*.err
*.markdown
*.html
index.md
.puppeteer.json
+14 −22
Original line number Diff line number Diff line
@@ -8,46 +8,37 @@ PDFOPTIONS += -V themeoptions:numbering=none -V themeoptions:progressbar=foot
PDFOPTIONS += -V fontsize=smaller
PDFOPTIONS += -V urlcolor=blue

REVEALOPTIONS = -t revealjs
REVEALOPTIONS += -F mermaid-filter
REVEALOPTIONS += --self-contained
REVEALOPTIONS += -V revealjs-url=reveal.js
REVEALOPTIONS += -V theme=white
REVEALOPTIONS += -V width=1920
REVEALOPTIONS += -V margin=0
REVEALOPTIONS += --slide-level=1

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) $(HTML) # La cible par défaut (all) exécute les cibles %.pdf
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 make puppeteer -k || true
	docker-compose run slides make all -k || true
	docker compose run slides

docker_clean: docker-compose.yml
	docker-compose run slides make clean -k || true
	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
	# @echo "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json

index.md: gen_index.sh
	$(shell ./gen_index.sh)

index:
	rm -f index.md
	./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 $@ $^

%.html: %.md metadata.yaml
	pandoc -s $(OPTIONS) $(REVEALOPTIONS) -o $@ $^

%.markdown: %.md metadata.yaml yq
	sed '1 { /^---/ { :a N; /\n---/! ba; d} }' $< > no_header
	grep -v -F -x -f  no_header $< > header.yaml
@@ -60,11 +51,12 @@ 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 
deploy: all index.html
	mkdir -p algo_cours
	cp *.pdf algo_cours
	cp index.html algo_cours

clean:
	rm -f *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json
	rm -rf *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json algo_cours *.err

.PHONY:	clean index puppeteer yq
.PHONY:	clean index.md puppeteer yq
+19 −363
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-22"
title: "Introduction aux algorithmes I"
date: "2025-09-16"
---

# Qu'est-ce qu'un algorithme?
@@ -42,7 +42,7 @@ de résoudre typiquement une classe de problèmes ou effectuer un calcul.

. . .

* Opérateurs (arthimétiques / booléens)
* Opérateurs (arithmétiques / booléens)
* Boucles;
* Structures de contrôle;
* Fonctions;
@@ -57,14 +57,12 @@ Nombre premier: nombre possédant deux diviseurs entiers distincts.
## Algorithme naïf (problème)

```C
est_premier(nombre) {
    si {
        pour tout i, t.q. 1 < i < nombre {
booléen est_premier(nombre) 
    si 
        pour tout i, t.q. 1 < i < nombre 
            i ne divise pas nombre
        }
    } alors vrai
    alors vrai
    sinon faux
}
```

. . .
@@ -80,14 +78,12 @@ est_premier(nombre) {
## Algorithme naïf (une solution)

```C
est_premier(nombre) { // fonction
    soit i := 2;       // variable, type, assignation
    tant que i < nombre { // boucle
        si nombre modulo i = 0 { // expression typée
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
    }
        i = i + 1
    retourne vrai // expression typée
```

@@ -103,7 +99,7 @@ bool est_premier(int nombre) {
        if (0 == nombre % i) { // is i divise nombre
            return false; // i n'est pas premier
        }
        i += 1; // sinon on incrémente i
        i = i + 1; // sinon on incrémente i
    }
    return true;
}
@@ -125,9 +121,9 @@ bool est_premier(int nombre) {

- Il existe une multitude d'options de compilation:

    ```bash
    $ gcc -O1 -std=c11 -Wall -Wextra -g porg.c -o prog -fsanitize=address 
    -fsanitize=leak -fsanitize=undefined
    ```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.
@@ -244,7 +240,7 @@ int main() {

# Quiz: compile ou compile pas?

## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033948)
## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501934)

# Types de base (1/4)

@@ -292,7 +288,7 @@ Type Signification

# Quiz: booléens

## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1032492)
## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501922)

<!-- TODO Quiz en ligne -->
<!-- ```C
@@ -336,7 +332,7 @@ if (x) { /* vrai */ }

# Quiz: conversions

## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033446)
## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501925)

<!-- TODO Quiz en ligne -->
<!-- ```C
@@ -351,343 +347,3 @@ bool d = 2.78; // 1
bool e = 1.0; // 1
``` -->
# Expressions et opérateurs (1/6)

Une expression est tout bout de code qui est **évalué**.

## Expressions simples

- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.

```C
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0;        // '0' est un litéral
int y = x;        // 'x' est une variable
int z = L;        // 'L' est une constante
```

## Expressions complexes

- Obtenues en combinant des *opérandes* avec des *opérateurs*

```C
int x;     // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
           // dont le résultat est affecté à 'x'
```

# Expressions et opérateurs (2/6)

## Opérateurs relationnels

Opérateurs testant la relation entre deux *expressions*:

  - `(a opérateur b)` retourne `1`{.C} si l'expression s'évalue à `true`{.C}, `0`{.C} si l'expression s'évalue à `false`{.C}.

| Opérateur | Syntaxe      | Résultat             |
|-----------|--------------|----------------------|
| `<`{.C}   | `a < b`{.C}  | 1 si a <  b; 0 sinon |
| `>`{.C}   | `a > b`{.C}  | 1 si a >  b; 0 sinon |
| `<=`{.C}  | `a <= b`{.C} | 1 si a <= b; 0 sinon |
| `>=`{.C}  | `a >= b`{.C} | 1 si a >= b; 0 sinon |
| `==`{.C}  | `a == b`{.C} | 1 si a == b; 0 sinon |
| `!=`{.C}  | `a != b`{.C} | 1 si a != b; 0 sinon |

# Expressions et opérateurs (3/6)

## Opérateurs logiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `&&`{.C}  | `a && b`{.C} | ET logique           |
| `||`{.C}  | `a || b`{.C} | OU logique           |
| `!`{.C}   | `!a`{.C}     | NON logique          |

# Quiz: opérateurs logiques

## [Quiz: opérateurs logiques](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033629)

<!-- TODO: Quiz -->
<!-- ```C
1 && 0 == 0
7 && 3 == 1
4 || 3 == 1
!34 == 0
!0 == 1

Soit n un unsigned char initialisé à 127:
!n == 0
``` -->

# Expressions et opérateurs (4/6)

## Opérateurs arithmétiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `+`{.C}   | `a + b`{.C}  | Addition             |
| `-`{.C}   | `a - b`{.C}  | Soustraction         |
| `*`{.C}   | `a * b`{.C}  | Multiplication       |
| `/`{.C}   | `a / b`{.C}  | Division             |
| `%`{.C}   | `a % b`{.C}  | Modulo               |

# Expressions et opérateurs (5/6)

## Opérateurs d'assignation

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `=`{.C}   | `a = b`{.C}  | Affecte la valeur `b` à la variable `a`     |
|           |              | et retourne la valeur de `b`                |
| `+=`{.C}  | `a += b`{.C} | Additionne la valeur de `b` à `a` et        |
|           |              | assigne le résultat à `a`.                  |
| `-=`{.C}  | `a -= b`{.C} | Soustrait la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `*=`{.C}  | `a *= b`{.C} | Multiplie la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `/=`{.C}  | `a /= b`{.C} | Divise la valeur de `b` à `a` et            |
|           |              | assigne le résultat à `a`.                  |
| `%=`{.C}  | `a %= b`{.C} | Calcule le modulo la valeur de `b` à `a` et |
|           |              | assigne le résultat à `a`.                  |

# Expressions et opérateurs (6/6)

## Opérateurs d'assignation (suite)

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `++`{.C}  | `++a`{.C}    | Incrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a += 1`).            |
| `--`{.C}  | `--a`{.C}    | Décrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a -= 1`).            |
| `++`{.C}  | `a++`{.C}    | Retourne `a`{.C} et incrémente `a` de 1.    |
| `--`{.C}  | `a--`{.C}    | Retourne `a`{.C} et décrémente `a` de 1.    |


# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (1/2)

## Syntaxe

```C
if (expression) {
    instructions;
} else if (expression) { // optionnel
                         // il peut y en avoir plusieurs
    instructions;
} else {
    instructions; // optionnel
}
```

```C
if (x) { // si x s'évalue à `vrai`
    printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
    printf("y vaut 8.\n");
} else {
    printf("Ni l'un ni l'autre.\n");
}
```

# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (2/2)

## Pièges

```C
int x, y;
x = y = 3;
if (x = 2)
    printf("x = 2 est vrai.\n");
else if (y < 8)
    printf("y < 8.\n");
else if (y == 3)
    printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
    printf("Ni l'un ni l'autre.\n");
    x = -1; // toujours évalué
```

# Quiz: `if ... else`{.C}

## [Quiz: `if ... else`{.C}](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033916)


# Structures de contrôle: `while`{.C}

## La boucle `while`{.C}

```C
while (condition) {
    instructions;
}
do {
    instructions;
} while (condition);
```

## La boucle `while`{.C}, un exemple

```C
int sum = 0; // syntaxe C99
while (sum < 10) {
    sum += 1;
}
do {
    sum += 10;
} while (sum < 100)
```

# Structures de contrôle: `for`{.C}

## La boucle `for`{.C}

```C
for (expression1; expression2; expression3) {
    instructions;
}
```

## La boucle `for`{.C}

```C
int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
    sum += i;
}

for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
    printf("C'est plus ésotérique.\n");
}
```

# Exercice: la factorielle

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un pseudo-code

. . .

```C
int factorielle(int n) {
    i = 1;
    fact = 1;
    pour i <= n {
        fact *= i;
        i += 1;
    }
}
```

# Exercice: la factorielle

\footnotesize

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un code en C

Quand vous avez fini postez le code sur le salon matrix.

. . .

```C
#include <stdio.h>
int main() {
   int nb = 10;
   int fact = 1;
   int iter = 2;
   while (iter <= nb) {
      fact *= iter;
      iter++;
   }
}
```

. . .

## Comment améliorer ce code? (notez ça sur une feuille)


# Entrées/sorties: `printf()`{.C} (1/2)

## Généralités

- La fonction `printf()`{.C} permet d'afficher du texte sur le terminal:

    ```C
    int printf(const char *format, ...);
    ```
- Nombre d'arguments variables.
- `format`{.C} est le texte, ainsi que le format (type) des variables à afficher.
- Les arguments suivants sont les expressions à afficher.

# Entrées/sorties: `printf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello world.\n");
    int val = 1;
    printf("Hello world %d time.\n", val);
    printf("%f squared is equal to %f.\n", 2.5, 2.5*2.5);
    return EXIT_SUCCESS;
}
```

# Entrées/sorties: `scanf()`{.C} (1/2)

## Généralités

- La fonction `scanf()`{.C} permet de lire du texte formaté entré au clavier:

    ```C
    int scanf(const char *format, ...);
    ```

- `format`{.C} est le format des variables à lire (comme `printf()`{.C}).
- Les arguments suivants sont les variables où sont stockées les valeurs lues.

# Entrées/sorties: `scanf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Enter 3 numbers: \n");
    int i, j, k;
    scanf("%d %d %d", &i, &j, &k);
    printf("You entered: %d %d %d\n", i, j, k);
    
    return EXIT_SUCCESS;
}
```

# Exercice: la factorielle en mieux

## Individuellement

1. Ajoutez des fonctionnalités à votre code.
2. Écrivez l'algorithme de calcul de deux façon différentes.
3. Pour celles et ceux qui ont fini pendant que les autres essaient: faites-le 
   en récursif (sans aide).

. . .

## Postez vos solutions sur matrix!

Original line number Diff line number Diff line
version: "3.3"
services:
    slides:
        #To use dockerfile : build: . 
        image:  omalaspinas/pandoc:latest
        environment:
            USER: 1000
            GROUP: 1000
        user: 1000:1000
        container_name: slides
        volumes:
            - ./:/data
        # entrypoint: ["make", "all"]
        entrypoint: ["make"]
        working_dir: /data
        # user: "$(id -u):$(id -g)"
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ for i in *.md; do
        fail "Error title field not found"
    fi
    i="${i%.*}"
    class="[${date} ${comp}](${PREFIX}${i}.pdf)"
    class="[${date}: ${comp}](${PREFIX}${i}.pdf)"
    classes+=("$class")
done
IFS=$'\n'
+21 −38
Original line number Diff line number Diff line
---
title: "Introduction générale"
date: "2020-09-16"
date: "2025-09-16"
---

# La hotline
@@ -11,59 +11,42 @@ Paul Albuquerque paul.albuquerque@hesge.ch B410
Orestis Malaspinas     orestis.malaspinas@hesge.ch       A401
--------------------   ------------------------------    --------------------

Utilisez le libre service (l'horaire sera fixé prochainement).
- 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).

Salon de discussion [Matrix](https://matrix.to/#/!tuZtXjUSPbnRfBsFXv:matrix.org?via=matrix.org), installez [element.io](https://element.io).

![](figs/matrix.png){width=20%}
    ![](figs/matrix_qr.png){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=13941>
  - Clé d'inscription: algo_2020_21
  - <https://cyberlearn.hes-so.ch/course/view.php?id=7276>
  - Clé d'inscription: algo_2025_26

- Programmation séquentielle en C
  - <https://cyberlearn.hes-so.ch/course/view.php?id=7282>
  - Clé d'inscription: prog_seq_2025_26

- Programmation Sequentielle en C
  - <https://cyberlearn.hes-so.ch/course/view.php?id=12399>
  - Clé d'inscription: PS_2018

# Organisation du module

* Deux cours, 50% chacun.
1. Algorithmes et structures de données:
## Cinq cours, 20% chacun.

1. Algorithmes et structures de données (2 semestres):
    * 1er semestre:
        * bases de programmation en C jusqu'à Noël.
        * bases de programmation en C jusqu'à Noël,
        * algorithmique jusqu'à fin janvier.
    * 2e semestre:
    * 2ème semestre:
        * algorithmique.
    * Deux évaluations écrites par semestre.
2. Programmation séquentielle en C
    * Deux évaluations écrites par semestre (1er sem.: 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 "petits" exercices illustrant les concepts d'algorithmique 
      (1-2 séances).
    * Évaluations:
        * Un projet de programmation.
        * Une évaluation machine.

# Sondage: expérience de programmation

## [Sondage: expérience de linux](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1291283)

## [Sondage: expérience de programmation](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1035242)

**Installez un lecteur de QR code s'il-vous-plaît.**

# Questions?

- N'hésitez pas à poser des *questions*, nous sommes là pour ça! [^1]
- Ne restez pas coincés pendant des jours sur un problème.
- Utilisez le *libre-service*!
- N'hésitez pas à faire des *retours*: *négatifs* ou *positifs*.

[^1]: Chaque étudiant·e·s a un quota de 5 questions par semestre.
    * Plusieurs exercices illustrant les concepts d'algorithmique.
    * Évaluations (4 tests machine).
3. Programmation système (semestre de printemps)

Original line number Diff line number Diff line
---
subtitle: "Algorithmique et structures de données, 2021-2022"
author: "Paul Albuquerque (B410), Pierre Künzli et Orestis Malaspinas (A401), ISC, HEPIA"
institute: En partie inspirés des supports de cours de P. Albuquerque
subtitle: "Algorithmique et structures de données, 2025-2026"
author: "P. Albuquerque (B410) et O. Malaspinas (A401), ISC, HEPIA"
institute: En partie inspiré 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"

slides_2021/.gitignore

0 → 100644
+6 −0
Original line number Diff line number Diff line
*.pdf
*.err
*.markdown
*.html
index.md
.puppeteer.json

slides_2021/Makefile

0 → 100644
+71 −0
Original line number Diff line number Diff line
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

REVEALOPTIONS = -t revealjs
REVEALOPTIONS += -F mermaid-filter
REVEALOPTIONS += --self-contained
REVEALOPTIONS += -V revealjs-url=reveal.js
REVEALOPTIONS += -V theme=white
REVEALOPTIONS += -V width=1920
REVEALOPTIONS += -V margin=0
REVEALOPTIONS += --slide-level=1

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 make puppeteer -k || true
	docker-compose run slides make all -k || true

docker_clean: docker-compose.yml
	docker-compose run slides make clean -k || true

puppeteer:
	@echo "Setting chromium to $(CHROMIUM) for puppeteer"
	@echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json

index:
	rm -f index.md
	./gen_index.sh

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 $@ $^

%.html: %.md metadata.yaml
	pandoc -s $(OPTIONS) $(REVEALOPTIONS) -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 
	mkdir -p algo_cours
	cp *.pdf algo_cours

clean:
	rm -f *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json

.PHONY:	clean index puppeteer yq

slides_2021/cours_1.md

0 → 100644
+693 −0
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-22"
---

# 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 (arthimé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
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
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 += 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:

    ```bash
    $ gcc -O1 -std=c11 -Wall -Wextra -g porg.c -o prog -fsanitize=address 
    -fsanitize=leak -fsanitize=undefined
    ```
    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=1033948)

# 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=1032492)

<!-- 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=1033446)

<!-- 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
``` -->

# Expressions et opérateurs (1/6)

Une expression est tout bout de code qui est **évalué**.

## Expressions simples

- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.

```C
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0;        // '0' est un litéral
int y = x;        // 'x' est une variable
int z = L;        // 'L' est une constante
```

## Expressions complexes

- Obtenues en combinant des *opérandes* avec des *opérateurs*

```C
int x;     // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
           // dont le résultat est affecté à 'x'
```

# Expressions et opérateurs (2/6)

## Opérateurs relationnels

Opérateurs testant la relation entre deux *expressions*:

  - `(a opérateur b)` retourne `1`{.C} si l'expression s'évalue à `true`{.C}, `0`{.C} si l'expression s'évalue à `false`{.C}.

| Opérateur | Syntaxe      | Résultat             |
|-----------|--------------|----------------------|
| `<`{.C}   | `a < b`{.C}  | 1 si a <  b; 0 sinon |
| `>`{.C}   | `a > b`{.C}  | 1 si a >  b; 0 sinon |
| `<=`{.C}  | `a <= b`{.C} | 1 si a <= b; 0 sinon |
| `>=`{.C}  | `a >= b`{.C} | 1 si a >= b; 0 sinon |
| `==`{.C}  | `a == b`{.C} | 1 si a == b; 0 sinon |
| `!=`{.C}  | `a != b`{.C} | 1 si a != b; 0 sinon |

# Expressions et opérateurs (3/6)

## Opérateurs logiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `&&`{.C}  | `a && b`{.C} | ET logique           |
| `||`{.C}  | `a || b`{.C} | OU logique           |
| `!`{.C}   | `!a`{.C}     | NON logique          |

# Quiz: opérateurs logiques

## [Quiz: opérateurs logiques](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033629)

<!-- TODO: Quiz -->
<!-- ```C
1 && 0 == 0
7 && 3 == 1
4 || 3 == 1
!34 == 0
!0 == 1

Soit n un unsigned char initialisé à 127:
!n == 0
``` -->

# Expressions et opérateurs (4/6)

## Opérateurs arithmétiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `+`{.C}   | `a + b`{.C}  | Addition             |
| `-`{.C}   | `a - b`{.C}  | Soustraction         |
| `*`{.C}   | `a * b`{.C}  | Multiplication       |
| `/`{.C}   | `a / b`{.C}  | Division             |
| `%`{.C}   | `a % b`{.C}  | Modulo               |

# Expressions et opérateurs (5/6)

## Opérateurs d'assignation

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `=`{.C}   | `a = b`{.C}  | Affecte la valeur `b` à la variable `a`     |
|           |              | et retourne la valeur de `b`                |
| `+=`{.C}  | `a += b`{.C} | Additionne la valeur de `b` à `a` et        |
|           |              | assigne le résultat à `a`.                  |
| `-=`{.C}  | `a -= b`{.C} | Soustrait la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `*=`{.C}  | `a *= b`{.C} | Multiplie la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `/=`{.C}  | `a /= b`{.C} | Divise la valeur de `b` à `a` et            |
|           |              | assigne le résultat à `a`.                  |
| `%=`{.C}  | `a %= b`{.C} | Calcule le modulo la valeur de `b` à `a` et |
|           |              | assigne le résultat à `a`.                  |

# Expressions et opérateurs (6/6)

## Opérateurs d'assignation (suite)

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `++`{.C}  | `++a`{.C}    | Incrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a += 1`).            |
| `--`{.C}  | `--a`{.C}    | Décrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a -= 1`).            |
| `++`{.C}  | `a++`{.C}    | Retourne `a`{.C} et incrémente `a` de 1.    |
| `--`{.C}  | `a--`{.C}    | Retourne `a`{.C} et décrémente `a` de 1.    |


# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (1/2)

## Syntaxe

```C
if (expression) {
    instructions;
} else if (expression) { // optionnel
                         // il peut y en avoir plusieurs
    instructions;
} else {
    instructions; // optionnel
}
```

```C
if (x) { // si x s'évalue à `vrai`
    printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
    printf("y vaut 8.\n");
} else {
    printf("Ni l'un ni l'autre.\n");
}
```

# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (2/2)

## Pièges

```C
int x, y;
x = y = 3;
if (x = 2)
    printf("x = 2 est vrai.\n");
else if (y < 8)
    printf("y < 8.\n");
else if (y == 3)
    printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
    printf("Ni l'un ni l'autre.\n");
    x = -1; // toujours évalué
```

# Quiz: `if ... else`{.C}

## [Quiz: `if ... else`{.C}](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033916)


# Structures de contrôle: `while`{.C}

## La boucle `while`{.C}

```C
while (condition) {
    instructions;
}
do {
    instructions;
} while (condition);
```

## La boucle `while`{.C}, un exemple

```C
int sum = 0; // syntaxe C99
while (sum < 10) {
    sum += 1;
}
do {
    sum += 10;
} while (sum < 100)
```

# Structures de contrôle: `for`{.C}

## La boucle `for`{.C}

```C
for (expression1; expression2; expression3) {
    instructions;
}
```

## La boucle `for`{.C}

```C
int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
    sum += i;
}

for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
    printf("C'est plus ésotérique.\n");
}
```

# Exercice: la factorielle

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un pseudo-code

. . .

```C
int factorielle(int n) {
    i = 1;
    fact = 1;
    pour i <= n {
        fact *= i;
        i += 1;
    }
}
```

# Exercice: la factorielle

\footnotesize

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un code en C

Quand vous avez fini postez le code sur le salon matrix.

. . .

```C
#include <stdio.h>
int main() {
   int nb = 10;
   int fact = 1;
   int iter = 2;
   while (iter <= nb) {
      fact *= iter;
      iter++;
   }
}
```

. . .

## Comment améliorer ce code? (notez ça sur une feuille)


# Entrées/sorties: `printf()`{.C} (1/2)

## Généralités

- La fonction `printf()`{.C} permet d'afficher du texte sur le terminal:

    ```C
    int printf(const char *format, ...);
    ```
- Nombre d'arguments variables.
- `format`{.C} est le texte, ainsi que le format (type) des variables à afficher.
- Les arguments suivants sont les expressions à afficher.

# Entrées/sorties: `printf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello world.\n");
    int val = 1;
    printf("Hello world %d time.\n", val);
    printf("%f squared is equal to %f.\n", 2.5, 2.5*2.5);
    return EXIT_SUCCESS;
}
```

# Entrées/sorties: `scanf()`{.C} (1/2)

## Généralités

- La fonction `scanf()`{.C} permet de lire du texte formaté entré au clavier:

    ```C
    int scanf(const char *format, ...);
    ```

- `format`{.C} est le format des variables à lire (comme `printf()`{.C}).
- Les arguments suivants sont les variables où sont stockées les valeurs lues.

# Entrées/sorties: `scanf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Enter 3 numbers: \n");
    int i, j, k;
    scanf("%d %d %d", &i, &j, &k);
    printf("You entered: %d %d %d\n", i, j, k);
    
    return EXIT_SUCCESS;
}
```

# Exercice: la factorielle en mieux

## Individuellement

1. Ajoutez des fonctionnalités à votre code.
2. Écrivez l'algorithme de calcul de deux façon différentes.
3. Pour celles et ceux qui ont fini pendant que les autres essaient: faites-le 
   en récursif (sans aide).

. . .

## Postez vos solutions sur matrix!

+602 −0
Original line number Diff line number Diff line
---
title: "B-Arbres"
date: "2022-04-13"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
---

# Les B-arbres

## Problématique

* Grands jeux de données (en 1970).
* Stockage dans un arbre, mais l'arbre tiens pas en mémoire.
* Regrouper les sous-arbres en **pages** qui tiennent en mémoire.

## Exemple

* 100 noeuds par page et l'arbre comporte $10^6$ noeuds:
    * Recherche B-arbre: $\log_{100}(10^6)=3$;
    * Recherche ABR: $\log_2(10^6)=20$.
* Si on doit lire depuis le disque: $10\mathrm{ms}$ par recherche+lecture:
    * $30\mathrm{ms}$ (lecture beaucoup plus rapide que recherche) vs $200\mathrm{ms}=0.2\mathrm{s}$.

## Remarques

* On sait pas ce que veut dire `B`: Bayer, Boeing, Balanced?
* Variante plus récente B+-arbres.

# Les B-arbres

## Illustration, arbre divisé en pages de 3 noeuds

![Arbre divisé en pages de 3 noeuds](figs/barbres_page3.png)

. . .

## Utilisation

* Bases de données (souvent très grandes donc sur le disque);
* Système de fichier.

# Les B-arbres

## Avantages

* Arbres moins profonds;
* Diminue les opération de rééquilibrage;
* Complexité toujours en $\log(N)$;

. . .

## Définition: B-arbre d'ordre $n$

* Chaque page d'un arbre contient au plus $2\cdot n$ *clés*;
* Chaque page (excepté la racine) contient au moins $n$ clés;
* Chaque page qui contient $m$ clés contient soit:
    * $0$ descendants;
    * $m+1$ descendants.
* Toutes les pages terminales apparaissent au même niveau.

# Les B-arbres

## Est-ce un B-arbre?

![B-arbre d'ordre 2.](figs/barbres_exemple.png)

. . .

## Oui!

* Dans chaque noeud les clés sont **triées**.
* Chaque page contient au plus $n$ noeuds: check;
* Chaque noeud avec $m$ clés a $m+1$ descendants;
* Toutes les feuilles apparaissent au même niveau.

# Les B-arbres

## Exemple de recherche: trouver `32`

![B-arbre d'ordre 2.](figs/barbres_exemple.png)
 
. . .

* Si `n` plus petit que la 1e clé ou plus grand que la dernière descendre.
* Sinon parcourir (par bissection ou séquentiellement) jusqu'à trouver ou descendre entre 2 éléments.

# Les B-arbres

## La recherche de la clé `C` algorithme 

0. En partant de la racine.
1. Si on est dans une feuille:
    * Si la `C` est dans une page, retourner la page;
    * Sinon c'est perdu.
2. Sinon:
    * Tant que `C > page` passer à la page suivante
    * Descendre

# Les B-arbres

## Disclaimer

* Inspiration de <https://en.wikipedia.org/wiki/B-tree>

## Exemples d'insertion: `1`

![B-arbre d'ordre 1.](figs/barbres_1.svg)
 
. . .

* L'arbre est vide, on insère juste dans la première page.

# Les B-arbres

## Exemples d'insertion: `2`

![B-arbre d'ordre 1. Nombre pages max = 2.](figs/barbres_2.svg)
 
. . .

* La première page est pas pleine, on insère dans l'ordre (après 1).

# Les B-arbres

## Exemples d'insertion: `3`

![B-arbre d'ordre 1.](figs/barbres_2.svg){width=50%}

* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `3`

![B-arbre d'ordre 1. Nombre pages max = 2.](figs/barbres_3.svg){width=50%}
 
. . .

* La page est pleine, on crée deux enfants.
* On choisit, `2`, la médiane de `1, 2, 3` et il est inséré à la racine.
* `1` descend à gauche, `3` descend à droite.

# Les B-arbres

## Exemples d'insertion: `4`

![B-arbre d'ordre 1.](figs/barbres_3.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `4`

![B-arbre d'ordre 1. Nombre enfants 0 ou 2.](figs/barbres_4.svg){width=50%}
 
. . .

* On pourrait insérer à droite de `2`, mais... ça ferait 2 parents pour 2 enfants (mais `m` parents => `m+1` enfants ou `0`);
* On descend à droite (`4 > 2`);
* On insère à droite de `3`.

# Les B-arbres

## Exemples d'insertion: `5`

![B-arbre d'ordre 1.](figs/barbres_4.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `5`

![B-arbre d'ordre 2.](figs/barbres_5.svg)
 
. . .

* On descend à droite (on peut pas insérer à la racine comme pour `4`);
* On dépasse la capacité de l'enfant droite;
* `4`, médiane de `3, 4, 5`, remonte à la racine;
* On crée un nouveau noeud à droite de `4`;
* La règle `m => m+1` est ok.

# Les B-arbres

## Exemples d'insertion: `6`

![B-arbre d'ordre 1.](figs/barbres_5.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `6`

![B-arbre d'ordre 2.](figs/barbres_6.svg)
 
. . .

* `6 > 4` on descend à droite;
* `6 > 5` et on a à la place à droite, on insère.

# Les B-arbres

## Exemples d'insertion: `7`

![B-arbre d'ordre 1.](figs/barbres_6.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `7`

![B-arbre d'ordre 2.](figs/barbres_7.svg){width=50%}
 
. . .

* `7 > 4` on descend à droite;
* `7 > 6` mais on a dépassé la capacité;
* `6` est la médiane de `5, 6, 7`, remonte à la racine;
* `5` reste à gauche, `7` à droite, mais `6` fait dépasser la capacité de la racine;
* `4` est la médiane de `2, 4, 6`, `4` remonte, `2` reste à gauche, `6` à droite.

# Les B-arbres

## L'algorithme d'insertion

0. Rechercher la feuille (la page a aucun enfant) où insérer;
1. Si la page n'est pas pleine insérer dans l'ordre croissant.
2. Si la page est pleine, on sépare la page en son milieu :
    1. On trouve la médiane, `M`, de la page;
    2. On met les éléments `< M` dans la page de gauche de `M` et les `> M` dans la page de droite de `M`;
    3. `M` est insérée récursivement dans la page parent.

# Les B-arbres

## Exercice: insérer `22, 45, 50` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex1.png)

. . .

![](figs/barbres_ex2.png)


# Les B-arbres

## Exercice: insérer `5` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex2.png)

. . .

![](figs/barbres_ex3.png)

# Les B-arbres

## Exercice: insérer `32, 55, 60` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex3.png)

. . .

![](figs/barbres_ex4.png)

# Les B-arbres

## Exercice: insérer `41` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex4.png)

. . .

![](figs/barbres_ex5.png)

# Les B-arbres

## Exercice (matrix, 15min)

* Insérer 20, 40, 10, 30, 15, 35, 7, 26, 18, 22, 5, 42, 13, 46, 27, 8, 32, 38, 24, 45, 25, 2, 14, 28, 32, 41,
* Dans un B-arbre d'ordre 2.

# Les B-arbres

## Structure de données

* Chaque page a une contrainte de remplissage, par rapport à l'ordre de l'arbre;
* Un noeud (page) est composé d'un tableau de clés/pointeurs vers les enfants;

```
P_0 | K_1 | P_1 | K_2 |  | P_i | K_{i+1} |  | P_{m-1} | K_m | P_m
```

* `P_0`, ..., `P_m` pointeurs vers enfants;
* `K_1`, ..., `K_m` les clés.
* Il y a `m+1` pointeurs mais `m` clés.
* Comment faire pour gérer l'insertion?

# Les B-arbres

## Faire un dessin de la structure de données (3min matrix)?

. . .

![Strcture d'une page de B-arbre d'ordre 2.](figs/barbres_struct.png)

1. On veut un tableau de `P_i, K_i => struct`;
2. `K_0` va être en "trop";
3. Pour simplifier l'insertion dans une page, on ajoute un élément de plus.

# Les B-arbres

## L'insertion cas noeud pas plein, insertion `4`?

![](figs/barbres_insert_easy.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_easy_after.svg){width=50%}

# Les B-arbres

## L'insertion cas noeud pas plein, insertion `N`

* On décale les éléments plus grand que `N`;
* On insère `N` dans la place "vide";
* Si la page n'est pas pleine, on a terminé.

# Les B-arbres

## L'insertion cas noeud plein, insertion `2`?

![](figs/barbres_insert_hard_before.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_hard_during.svg){width=50%}

# Les B-arbres

## L'insertion cas noeud plein, promotion `3`?

![](figs/barbres_insert_hard_during.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_hard_after.svg)

# Les B-arbres

## L'insertion cas noeud plein, insertion `N`

* On décale les éléments plus grand que `N`;
* On insère `N` dans la place "vide";
* Si la page est pleine:
    * On trouve la valent médiance `M` de la page (quel indice?);
    * On crée une nouvelle page de droite;
    * On copie les valeur à droite de `M` dans la nouvelle page;
    * On promeut `M` dans la page du dessus;
    * On connecte le pointeur de gauche de `M` et de droite de `M` avec l'ancienne et la nouvelle page respectivement.

# Les B-arbres

## Pseudo-code structure de données (3min, matrix)?

. . .

```C
struct page
    entier ordre, nb
    element tab[2*ordre + 2]
```

```C
struct element
    int clé
    page pg
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
booléen est_feuille(page)     // la page est elle une feuille?
entier position(page, valeur) // à quelle indice on insère?
booléen est_dans_page(page, valeur) // la valeur est dans la page
```

. . .

```C
booléen est_feuille(page) 
    retourne (page.tab[0].pg == vide)

entier position(page, valeur)
    i = 0
    tant que i < page.nb && val >= page.tab[i+1].clef
        i += 1
    retourne i

booléen est_dans_page(page, valeur)
    i = position(page, valeur)
    retourne (page.nb > 0 && page.tab[i].val == valeur)
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
page nouvelle_page(ordre)  // creer une page
rien liberer_memoire(page) // liberer tout un arbre!
```
. . .

```C
page nouvelle_page(ordre)
    page = allouer(page)
    page.ordre = ordre
    page.nb = 0
    page.tab = allouer(2*ordre+2)
    retourner page

rien liberer_memoire(page)
    si est_feuille(page)
        liberer(page.tab)
        liberer(page)
    sinon
        pour fille dans page.tab
            liberer_memoire(fille)
        liberer(page.tab)
        liberer(page)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page recherche(page, valeur) // retourner la page contenant
                             // la valeur ou vide 
```

. . .

```C
page recherche(page, valeur)
    si est_dans_page(page, valeur)
        retourne page
    sinon si est_feuille(page) 
        retourne vide
    sinon
        recherche(page.tab[position(page, valeur)], valeur)
```

# Les B-arbres

## Les fonctions

```C
page inserer_valeur(page, valeur) // inserer une valeur
```

. . .

```C
page inserer_valeur(page, valeur)
    element = nouvel_element(valeur)
    // on change element pour savoir s'il faut le remonter
    inserer_element(page, element) 
    si element.page != vide && page.nb > 2*page.ordre
        // si on atteint le sommet!
        page = ajouter_niveau(page, element) 
    retourne page
```

# Les B-arbres

## Les fonctions

```C
rien inserer_element(page, element) // inserer un element et voir s'il remonte
```

. . .

```C
rien inserer_element(page, element)
    si est_feuille(page)
        placer(page, element)
    sinon
        sous_page = page.tab[position(page, element)].page
        inserer_element(sous_page, element)
        // un element a été promu
        si element.page != vide
            placer(page, element)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien placer(page, element) // inserer un élément
```

. . .

```C
rien placer(page, element)
    pos = position(page, element.clé)
    pour i de 2*page.ordre à pos+1
        page.tab[i+1] = page.tab[i]
    page.tab[pos+1] = element
    page.nb += 1
    si page.nb > 2*page.ordre
        scinder(page, element)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien scinder(page, element) // casser une page et remonter
```

. . .

```C
rien scinder(page, element)
    new_page = new_page(page.ordre)
    new_page.nb = page.ordre
    pour i de 0 à ordre inclu
        new_page.tab[i] = page.tab[i+ordre+1]
    element.clé = page.tab[ordre+1].clé
    element.page = new_page
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page ajouter_niveau(page, element) // si on remonte à la racine...
                                   // on doit créer une nouvelle racine
```

. . .

```C
page ajouter_niveau(page, element) 
    tmp = nouvelle_page(page.ordre)
    tmp.tab[0].page = page
    tmp.tab[1].clé = element.clé
    tmp.tab[1].page = element.page
    retourne tmp
```


<!-- # Les B-arbres -->

<!-- ## Structure de données en C (3min, matrix) -->

<!-- . . . -->

<!-- ```C -->
<!-- typedef struct _page { -->
<!--     int order, nb; -->
<!--     struct _element *tab; -->
<!-- } page; -->
<!-- ``` -->

<!-- ```C -->
<!-- typedef struct element { -->
<!--     int key; -->
<!--     struct _page *pg; -->
<!-- } element; -->
<!-- ``` -->
+445 −0
Original line number Diff line number Diff line
---
title: "B-Arbres"
date: "2022-05-03"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
---

# Rappel: Les B-arbres

## Pourquoi utiliser un B-arbre?

. . .

## À quoi ressemble un B-arbre?

. . .

## Qu'est-ce qu'un B-arbre d'ordre $n$

* Chaque page d'un arbre contient au plus $2\cdot n$ *clés*;
* Chaque page (excepté la racine) contient au moins $n$ clés;
* Chaque page qui contient $m$ clés contient soit:
    * $0$ descendants;
    * $m+1$ descendants.
* Toutes les pages terminales apparaissent au même niveau.


# Rappel: Les B-arbres

## Quelques propriétés

* Dans chaque noeud les clés sont **triées**.
* Chaque page contient au plus $n$ noeuds: check;
* Chaque noeud avec $m$ clés a $m+1$ descendants;
* Toutes les feuilles apparaissent au même niveau.

# Les B-arbres

## Exemple de recherche: trouver `32`

![B-arbre d'ordre 2.](figs/barbres_exemple.png)
 
. . .

* Si `n` plus petit que la 1e clé ou plus grand que la dernière descendre.
* Sinon parcourir (par bissection ou séquentiellement) jusqu'à trouver ou descendre entre 2 éléments.

# Les B-arbres

## La recherche de la clé `C` algorithme 

0. En partant de la racine.
1. Si on est dans une feuille:
    * Si la `C` est dans une page, retourner la page;
    * Sinon c'est perdu.
2. Sinon:
    * Tant que `C > page` passer à la page suivante
    * Descendre


# Les B-arbres

## Exercice: insérer `22, 45, 50, 5, 32, 55, 60, 41` dans l'arbre d'ordre 2

![](figs/barbres_ex1.png)

. . .

![](figs/barbres_ex5.png)

# Les B-arbres

## L'algorithme d'insertion

0. Rechercher la feuille (la page a aucun enfant) où insérer;
1. Si la page n'est pas pleine insérer dans l'ordre croissant.
2. Si la page est pleine:
    1. On décale les éléments plus grand que `N`;
    2. On insère `N` dans la place "vide";
    3. On trouve la valeur médiane `M` de la page (quel indice?);
    4. On crée une nouvelle page de droite;
    5. On copie les valeur à droite de `M` dans la nouvelle page;
    6. On promeut `M` dans la page du dessus;
    7. On connecte le pointeur de gauche de `M` et de droite de `M` avec l'ancienne et la nouvelle page respectivement.

# Les B-arbres

## Pseudo-code structure de données (3min, matrix)?

. . .

```C
struct page
    entier ordre, nb
    element tab[2*ordre + 2]
```

```C
struct element
    int clé
    page pg
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
booléen est_feuille(page)     // la page est elle une feuille?
entier position(page, valeur) // à quelle indice on insère?
booléen est_dans_page(page, valeur) // la valeur est dans la page
```

. . .

```C
booléen est_feuille(page) 
    retourne (page.tab[0].pg == vide)

entier position(page, valeur)
    i = 0
    tant que i < page.nb && val >= page.tab[i+1].clef
        i += 1
    retourne i

booléen est_dans_page(page, valeur)
    i = position(page, valeur)
    retourne (page.nb > 0 && page.tab[i].clef == valeur)
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
page nouvelle_page(ordre)  // creer une page
rien liberer_memoire(page) // liberer tout un arbre!
```
. . .

```C
page nouvelle_page(ordre)
    page = allouer(page)
    page.ordre = ordre
    page.nb = 0
    page.tab = allouer(2*ordre+2)
    retourner page

rien liberer_memoire(page)
    si est_feuille(page)
        liberer(page.tab)
        liberer(page)
    sinon
        pour fille dans page.tab
            liberer_memoire(fille)
        liberer(page.tab)
        liberer(page)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page recherche(page, valeur) // retourner la page contenant
                             // la valeur ou vide 
```

. . .

```C
page recherche(page, valeur)
    si est_dans_page(page, valeur)
        retourne page
    sinon si est_feuille(page)
        retourne vide
    sinon
        recherche(page.tab[position(page, valeur)], valeur)
```

# Les B-arbres

## Les fonctions

```C
page inserer(page, valeur) // inserer une valeur
```

. . .

```C
page inserer(page, valeur)
    element = nouvel_element(valeur)
    // on change element pour savoir s'il faut le remonter
    inserer_element(page, element) 
    si element != vide && element.page != vide
        // si on atteint le sommet
        page = ajouter_niveau(page, element) 
    retourne page
```

# Les B-arbres

## Les fonctions

```C
// inserer un element et voir s'il remonte
rien inserer_element(page, element) 
```

. . .

```C
rien inserer_element(page, element)
    si est_feuille(page)
        placer(page, element)
    sinon
        sous_page = page.tab[position(page, element)].page
        inserer_element(sous_page, element)
        si element != vide && element.page != vide
            placer(page, element)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien placer(page, element) // inserer un élément
```

. . .

```C
rien placer(page, element)
    i = position(page, element.clef)
    pour i de 2*page.ordre à i+1
        page.tab[i+1] = page.tab[i]
    page.tab[i+1] = element
    page.nb += 1
    si page.nb > 2*page.ordre
        scinder(page, element)
    sinon
        element = vide
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien scinder(page, element) // casser une page et remonter
```

. . .

```C
rien scinder(page, element)
    new_page = new_page(page.ordre)
    new_page.nb = page.ordre
    pour i de 0 à ordre inclu
        new_page.tab[i] = page.tab[i+ordre+1]
    element.clef = page.tab[ordre+1].clé
    element.page = new_page
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page ajouter_niveau(page, element) // si on remonte à la racine...
                                   // on doit créer une nouvelle racine
```

. . .

```C
page ajouter_niveau(page, element) 
    tmp = nouvelle_page(page.ordre)
    tmp.tab[0].page = page
    tmp.tab[1].clef = element.clef
    tmp.tab[1].page = element.page
    retourne tmp
```

# Les B-arbres: suppression

## Cas simplissime

![Suppression de 25.](figs/barbres_ordre2_supp1.svg){width=80%}

. . .

![25 supprimé, on décale juste 27.](figs/barbres_ordre2_supp2.svg){width=80%}

# Les B-arbres: suppression

## Cas simple


![Suppression de 27.](figs/barbres_ordre2_supp2.svg){width=60%}

. . .

* On retire 27, mais....
    * Chaque page doit avoir au moins 2 éléments.
    * On doit déplacer des éléments dans une autre feuille! Mais comment?

. . .

![La médiane de la racine descend, fusion de 20 à gauche, et suppression à droite.](figs/barbres_ordre2_supp3.svg){width=60%}

# Les B-arbres: suppression

## Cas moins simple

![Suppression de 5.](figs/barbres_ordre2_supp4.svg){width=60%}

. . .

* Un élément à droite, comment on fait?
    * Remonter `7`, serait ok si racine, mais... c'est pas forcément.
    * On redistribue les feuilles.

. . .

![Descente de `3`, remontée médiane des feuilles `2`, .](figs/barbres_ordre2_supp5.svg){width=60%}

# Les B-arbres: suppression

## Cas ultra moins simple

![Suppression de 3.](figs/barbres_ordre2_supp6.svg){width=60%}

. . .

* `7` seul:
    * Fusionner les feuilles et redistribuer, comment?

. . .

![Descendre `-1`, déplacer `7` à gauche, et décaler les éléments de droite au milieu.](figs/barbres_ordre2_supp7.svg){width=60%}

# Les B-arbres: suppression

## Cas ultra moins simple

![On a pas fini...](figs/barbres_ordre2_supp7.svg){width=60%}

. . .

* `8` est seul, c'est plus un B-arbre :
    * Fusionner le niveau 2 et redistribuer, comment?

. . .

![Fusionner `8`, `17`, `22` et descendre `12`.](figs/barbres_ordre2_supp8.svg){width=40%}

. . .

* La profondeur a diminué de 1.

# Les B-arbres: suppression

## Algorithme pour les feuilles!

* Si la clé est supprimée d'une feuille:
    * Si on a toujours `n` (ordre de l'arbre) clés dans la feuille on décale simplement les clés.
    * Sinon on combine (récursivement) avec le noeud voisin et on descend la clé médiane.

# Les B-arbres: suppression

## Cas non-feuille!

![Suppression de 8.](figs/barbres_ordre2_supp9.svg){width=60%}

. . .

* On sait comment effacer une valeur d'une feuille, donc?

. . .

![Échanger le `8` avec le plus grand du sous-arbre de gauche.](figs/barbres_ordre2_supp10.svg){width=60%}

* Ensuite?

# Les B-arbres: suppression

## Cas non-feuille!

![Suppression de 8.](figs/barbres_ordre2_supp10.svg){width=60%}

. . .

* On sait comment effacer une valeur d'une feuille!

. . .

![Yaka enlever le 8 de la feuille comme avant!](figs/barbres_ordre2_supp11.svg){width=60%}

# Les B-arbres: suppression

## Algorithme pour les non-feuilles!

* Si la clé est supprimée d'une page qui n'est pas une feuille:
    * On échange la valeur avec la valeur de droite de la page de gauche
    * On supprime comme pour une feuille!

## Et maintenant des exos par millions!


<!-- # Les B-arbres -->

<!-- ## Structure de données en C (3min, matrix) -->

<!-- . . . -->

<!-- ```C -->
<!-- typedef struct _page { -->
<!--     int order, nb; -->
<!--     struct _element *tab; -->
<!-- } page; -->
<!-- ``` -->

<!-- ```C -->
<!-- typedef struct element { -->
<!--     int key; -->
<!--     struct _page *pg; -->
<!-- } element; -->
<!-- ``` -->
+883 −0
Original line number Diff line number Diff line
---
title: "Graphes - Généralités"
date: "2022-05-03"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
---

# Historique

**Un mini-peu d'histoire...**

## L. Euler et les 7 ponts de Koenigsberg:

* Existe-t-il une promenade sympa, passant **une seule fois** par les 7 ponts et revenant au point de départ?

![Les ponts c'est beau. Source: Wikipédia, <https://bit.ly/37h0yOG>](figs/Konigsberg_bridges.png){width=50%}

. . .

* Réponse: ben non!

# Utilisation quotidienne

## Réseau social

![Source, Wikipedia: <https://bit.ly/3kG6cgo>](figs/Social_Network.svg){width=40%}

* Chaque sommet est un individu.
* Chaque trait une relation d'amitié.
* Miam, Miam, Facebook.

# Utilisation quotidienne

## Moteurs de recherche

![Source, Wikipedia: <https://bit.ly/3kG6cgo>](figs/PageRanks-Example.svg){width=40%}

* Sommet est un site.
* Liens sortants;
* Liens entrants;
* Notion d'importance d'un site: combien de liens entrants, pondérés par l'importance du site.
* Miam, Miam, Google (PageRank).

# Introduction

## Définition, plus ou moins

* Un graphe est un ensemble de sommets, reliés par des lignes ou des flèches.

![Deux exemples de graphes.](figs/ex_graphes.png)

* Des sommets (numérotés 1 à 6);
* Connectés ou pas par des traits ou des flèches!

# Généralités

## Définitions

* Un **graphe** $G(V, E)$ est constitué
    * $V$: un ensemble de sommets;
    * $E$: un ensemble d'arêtes.
* Une **arête** relie une **paire** de sommets de $V$.

## Remarques

* Il y a **au plus** une arête $E$ par paire de sommets de $V$.
* La **complexité** d'un algorithme dans un graphe se mesure en terme de $|E|$ et $|V|$, le nombre d'éléments de $E$ et $V$ respectivement.

# Généralités

## Notations

* Une arête d'un graphe **non-orienté** est représentée par une paire **non-ordonnée** $(u,v)=(v,u)$, avec $u,v\in V$.
* Les arêtes ne sont pas orientées dans un graphe non-orienté (elles sont bi-directionnelles, peuvent être parcourues dans n'importe quel ordre).

## Exemple


::: columns

:::: column

![Un graphe non-orienté.](figs/ex_graphe_non_oriente.svg)


::::

:::: column

## Que valent $V$, $|V|$, $E$, et $|E|$?

. . .

\begin{align*}
V&=\{1, 2, 3, 4\},\\
|V|&=4,\\
E&=\{(1,2),(2,3),(2,4),(4,1)\},\\
|E|&=4.
\end{align*}

::::

:::

# Généralités

## Notations

* Une arête d'un graphe **orienté** est représentée par une paire **ordonnée** $(u,v)\neq(v,u)$, avec $u,v\in V$.
* Les arêtes sont orientées dans un graphe orienté (étonnant non?).

## Exemple


::: columns

:::: column

![Un graphe non-orienté.](figs/ex_graphe_oriente.svg)


::::

:::: column

## Que valent $V$, $|V|$, $E$, et $|E|$?

. . .

\begin{align*}
V&=\{1, 2, 3, 4\},\\
|V|&=4,\\
E&=\{(1,2),(2,3),(2,4),(4,1),(4,2)\},\\
|E|&=5.
\end{align*}

::::

:::

# Généralités

## Définition

* Le somme $v$ est **adjacent** au sommet $u$, si et seulement si $(u,v)\in E$;
* Si un graphe non-orienté contient une arête $(u,v)$, $v$ est adjacent à $u$ et $u$ et adjacent à $v$.

## Exemple

::: columns

:::: column

![Sommet $a$  adjacent à $c$, $c$ adjacent à $a$.](figs/ex_adj_non_or.svg){width=80%}

::::

:::: column

![Sommet $a$  adjacent à $c$.](figs/ex_adj_or.svg){width=80%}

::::

:::

# Généralités

## Définition

* Un **graphe pondéré** ou **valué** est un graphe dont chaque arête a un
  poids associé, habituellement donné par une fonction de pondération $w:E\rightarrow\mathbb{R}$.

## Exemples

![Graphe pondéré orienté (gauche) et non-orienté (droite).](figs/ex_graph_pond.pdf){width=80%}


# Généralités

## Définition

* Dans un graphe $G(V,E)$, une **chaîne** reliant un sommet $u$ à un sommet $v$ est une suite d'arêtes entre les sommets, $w_0$, $w_1$, ..., $w_k$, telles que 
$$
(w_i, w_{i+1})\in E,\quad u=w_0,\quad v=w_k,\quad \mbox{pour }0\leq i< k,
$$
avec $k$ la longueur de la chaîne (le nombre d'arêtes du chemin).

## Exemples

![Illustration d'une chaîne, ou pas chaîne dans un graphe.](figs/ex_graphe_chaine.pdf){width=80%}

# Généralités

## Définition

* Une **chaîne élémentaire** est une chaîne dont tous les sommets sont distincts, sauf les extrémités qui peuvent être égales

## Exemples

![Illustration d'une chaîne élémentaire.](figs/ex_graphe_chaine_elem.pdf){width=80%}

# Généralités

## Définition

* Une **boucle** est une arête $(v,v)$ d'un sommet vers lui-même.

## Exemples

![Illustration d'une boucle.](figs/ex_graphe_boucle.pdf){width=40%}

# Généralités

## Définition

* Un graphe non-orienté est dit **connexe**, s'il existe un chemin reliant n'importe quelle paire de sommets distincts.

## Exemples

\

::: columns

:::: column

![Graphe connexe. Source, Wikipédia: <https://bit.ly/3yiUzUv>](figs/graphe_connexe.svg){width=80%}

::::

:::: column
![Graphe non-connexe avec composantes connexes. Source, Wikipédia: <https://bit.ly/3KJB76d>](figs/composantes_connexes.svg){width=60%}

::::

:::

# Généralités

## Définition

* Un graphe orienté est dit **fortement connexe**, s'il existe un chemin reliant n'importe quelle paire de sommets distincts.

## Exemples

\

::: columns

:::: column

![Graphe fortement connexe.](figs/ex_graph_fort_connexe.pdf){width=60%}

::::

:::: column

![Composantes fortement connexes. Source, Wikipédia: <https://bit.ly/3w5PL2l>](figs/composantes_fortement_connexes.svg){width=100%}

::::

:::

# Généralités

## Définition

* Un **cycle** dans un graphe *non-orienté* est une chaîne de longueur $\leq 3$ telle que le 1er sommet de la chaîne est le même que le dernier, et dont les arêtes sont distinctes.
* Pour un graphe *orienté* on parle de **circuit**.
* Un graphe sans cycles est dit **acyclique**.

## Exemples

![Illustration de cycles, ou pas.](figs/ex_graphe_cycle.pdf){width=100%}

# Question de la mort

* Qu'est-ce qu'un graphe connexe acyclique?

. . .

* Un arbre!

# Représentations

* La complexité des algorithmes sur les graphes s'expriment en fonction du nombre de sommets $V$, et du nombre d'arêtes $E$:
    * Si $|E|\sim |V|^2$, on dit que le graphe est **dense**.
    * Si $|E|\sim |V|$, on dit que le graphe est **peu dense**.
* Selon qu'on considère des graphes denses ou peu denses, différentes structure de données peuvent être envisagées.

## Question

* Comment peut-on représenter un graphe informatiquement? Des idées (réflexion de quelques minutes)?

. . .

* Matrice/liste d'adjacence.

# Matrice d'adjacence

* Soit le graphe $G(V,E)$, avec $V=\{1, 2, 3, ..., n\}$;
* On peut représenter un graphe par une **matrice d'adjacence**, $A$, de dimension $n\times n$ définie par
$$
A_{ij}=\left\{ \begin{array}{ll}
         1 & \mbox{si } i,j\in E,\\
         0 & \mbox{sinon}.
         \end{array} \right.
$$


::: columns

:::: column

## Exemple

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    1---2;
    1---4;
    2---5;
    4---5;
    5---3;
```

::::

:::: column

\footnotesize

## Quelle matrice d'adjacence? 

. . .

```
   || 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
 1 || 0 | 1 | 0 | 1 | 0
---||---|---|---|---|---
 2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 3 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 4 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 5 || 0 | 1 | 1 | 1 | 0
```

::::

:::

# Matrice d'adjacence

## Remarques

* Zéro sur la diagonale.
* La matrice d'un graphe non-orienté est symétrique

$$
A_{ij}=A_{ji}, \forall i,j\in[1,n]
$$.

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    1---2;
    1---4;
    2---5;
    4---5;
    5---3;
```

::::

:::: column

\footnotesize

```
   || 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
 1 || 0 | 1 | 0 | 1 | 0
---||---|---|---|---|---
 2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 3 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 4 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 5 || 0 | 1 | 1 | 1 | 0
```

::::

:::

# Matrice d'adjacence

* Pour un graphe orienté (digraphe)

::: columns

:::: column

## Exemple

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    2-->1;
    1-->4;
    2-->5;
    5-->2;
    4-->5;
    5-->3;
```

::::

:::: column

\footnotesize

## Quelle matrice d'adjacence? 

. . .

```
   || 1 | 2 | 3 | 4 | 5
===||===|===|===|===|===
 1 || 0 | 0 | 0 | 1 | 0
---||---|---|---|---|---
 2 || 1 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 3 || 0 | 0 | 0 | 0 | 0
---||---|---|---|---|---
 4 || 0 | 0 | 0 | 0 | 1
---||---|---|---|---|---
 5 || 0 | 1 | 1 | 0 | 0
```

::::

:::

* La matrice d'adjacence n'est plus forcément symétrique
$$
A_{ij}\neq A_{ji}.
$$

# Stockage

* Quel est l'espace nécessaire pour stocker une matrice d'adjacence pour un graphe orienté?

. . .

* $\mathcal{O}(|V|^2)$.
* Quel est l'espace nécessaire pour stocker une matrice d'adjacence pour un graphe non-orienté?

. . .

* $\mathcal{O}(|V|-1)|V|/2$.

# Considérations d'efficacité

* Dans quel type de graphes la matrice d'adjacence est utile?

. . .

* Dans les graphes denses.
* Pourquoi?

. . .

* Dans les graphes peu denses, la matrice d'adjacence est essentiellement composée de `0`.

## Remarque

* Dans la majorité des cas, les grands graphes sont peu denses.
* Comment représenter un graphe autrement?

# La liste d'adjacence (non-orienté)

* Pour chaque sommet $v\in V$, stocker les sommets adjacents à $v$-
* Quelle structure de données pour la liste d'adjacence?

. . .

* Tableau de liste chaînée, vecteur (tableau dynamique), etc.


::: columns

:::: column

## Exemple

![Un graphe non-orienté.](figs/ex_graph_adj.pdf){width=80%}

::::

:::: column


## Quelle liste d'adjacence? 

. . .

![La liste d'adjacence.](figs/ex_graph_list_adj.pdf)


::::

:::

# La liste d'adjacence (orienté)


::: columns

:::: column

## Quelle liste d'adjacence pour...

* Matrix (2min)

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    0-->1;
    0-->2;
    1-->2;
    3-->0;
    3-->1;
    3-->2;
```

::::

:::: column

```











```


::::

:::

# Complexité

## Stockage

* Quelle espace est nécessaire pour stocker une liste d'adjacence (en fonction de $|E|$ et $|V|$)?

. . .

$$
\mathcal{O}(|E|)
$$

* Pour les graphes *non-orientés*: $\mathcal{O}2|E|$.
* Pour les graphes *orientés*: $\mathcal{O}|E|$.

## Définition

* Le **degré** d'un sommet $v$, est le nombre d'arêtes incidentes du sommet (pour les graphes orientés on a un degré entrant ou sortant).
* Comment on retrouve le degré de chaque sommet avec la liste d'adjacence?

. . .

* C'est la longueur de la liste chaînée.


# Parcours

* Beaucoup d'applications nécessitent de parcourir des graphes:
    * Trouver un chemin d'un sommet à un autre;
    * Trouver si le graphe est connexe;
* Il existe *deux* parcours principaux:
    * en largeur (Breadth-First Search);
    * en profondeur (Depth-First Search).
* Ces parcours créent *un arbre* au fil de l'exploration (si le graphe est non-connexe cela crée une *forêt*, un ensemble d'arbres).

# Illustration: parcours en largeur

![Le parcours en largeur.](figs/parcours_larg.pdf){width=80%}

# Exemple

## Étape par étape (blanc non-visité)

![Initialisation.](figs/parcours_larg_0.pdf){width=50%}

## Étape par étape (gris visité)

![On commence en `x`.](figs/parcours_larg_1.pdf){width=50%}

# Exemple

## Étape par étape

![On commence en `x`.](figs/parcours_larg_1.pdf){width=50%}

## Étape par étape (vert à visiter)

![Vister `w`, `t`, `y`.](figs/parcours_larg_2.pdf){width=50%}

# Exemple

## Étape par étape

![Vister `w`, `t`, `y`.](figs/parcours_larg_2.pdf){width=50%}

## Étape par étape

![`w`, `t`, `y` visités. `u`, `s` à visiter.](figs/parcours_larg_3.pdf){width=50%}

# Exemple

## Étape par étape

![`w`, `t`, `y` visités. `u`, `s` à visiter.](figs/parcours_larg_3.pdf){width=50%}

## Étape par étape

![`u`, `s`, visités. `r` à visiter.](figs/parcours_larg_4.pdf){width=50%}

# Exemple

## Étape par étape

![`u`, `s`, visités. `r` à visiter.](figs/parcours_larg_4.pdf){width=50%}

## Étape par étape

![`r` visité. `v` à visiter.](figs/parcours_larg_5.pdf){width=50%}

# Exemple

## Étape par étape

![`r` visité. `v` à visiter.](figs/parcours_larg_5.pdf){width=50%}

## Étape par étape

![The end. Plus rien à visiter!](figs/parcours_larg_6.pdf){width=50%}

# En faisant ce parcours...


::: columns

:::: column

## Du parcours de l'arbre

![](figs/parcours_larg_6.pdf){width=100%}

::::

:::: column

## Quel arbre est créé par le parcours (2min)?

. . .

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    0[x]-->1[w];
    0-->2[t];
    0-->3[y];
    2-->9[u];
    1-->4[s];
    4-->5[r];
    5-->6[v];
```

::::

:::

## Remarques

* Le parcours dépend du point de départ dans le graphe.
* L'arbre sera différent en fonction du noeud de départ, et de l'ordre de parcours des voisins d'un noeud.

# Le parcours en largeur

## L'algorithme, idée générale (3min, matrix)?

. . .

```C
v = un sommet du graphe
i = 1
pour sommet dans graphe et sommet non-visité
    visiter(v, sommet, i) // marquer sommet à distance i visité 
    i += 1
```

## Remarque

* `i` est la distance de plus cours chemin entre `v` et les sommets en cours de visite.


# Le parcours en largeur

## L'algorithme, pseudo-code (3min, matrix)?

* Comment garder la trace de la distance?

. . .

* Utilisation d'une **file**

. . .

```C
initialiser(graphe) // tous sommets sont non-visités
file = visiter(sommet, vide) // sommet est un sommet du graphe au hasard
tant que !est_vide(file)
    v = défiler(file)
    file = visiter(v, file)
```

## Que fait visiter?

```
file visiter(sommet, file)
    sommet = visité
    pour w = chaque arête de sommet
        si w != visité
            file = enfiler(file, w)
    retourne file
```

# Exercice (5min)

## Appliquer l'algorithme sur le graphe

![](figs/parcours_larg_0.pdf){width=50%}

* En partant de `v`, `s`, ou `u` (par colonne de classe).
* Bien mettre à chaque étape l'état de la file.

# Complexité du parcours en largeur

## Étape 1

* Extraire un sommet de la file;

## Étape 2

* Traîter tous les sommets adjacents.

## Quelle est la complexité?

. . .

* Étape 1: $\mathcal{O}(|V|)$,
* Étape 2: $\mathcal{O}(2|E|)$,
* Total: $\mathcal{O}(|V| + |2|E|)$.

# Exercice

* Établir la liste d'adjacence et appliquer l'algorithme de parcours en largeur au graphe

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    1---2;
    1---3;
    1---4;
    2---3;
    2---6;
    3---6;
    3---4;
    3---5;
    4---5;
```


# Illustration: parcours en profondeur

![Le parcours en profondeur. À quel parcours d'arbre cela ressemble-t-il?](figs/parcours_prof.pdf){width=80%}

# Parcours en profondeur

## Idée générale

* Initialiser les sommets comme non-lus
* Visiter un sommet
* Pour chaque sommet visité, on visite un sommet adjacent s'il est pas encore visité récursivement.

## Remarque

* La récursivité est équivalent à l'utilisation d'une **pile**.

# Parcours en profondeur

## Pseudo-code (5min)

. . .

```C
initialiser(graphe) // tous sommets sont non-visités
pile = visiter(sommet, vide) // sommet est un sommet du graphe au hasard
tant que !est_vide(pile)
    v = dépiler(pile)
    pile = visiter(v, pile)
```

## Que fait visiter?

. . .

```C
pile visiter(sommet, pile)
    sommet = visité
    pour w = chaque arête de sommet
        si w != visité
            pile = empiler(pile, w)
    retourne pile
```


# Exercice

* Établir la liste d'adjacence et appliquer l'algorithme de parcours en profondeur au graphe

```{.mermaid format=pdf width=400 loc=figs/}
graph LR;
    1---2;
    1---3;
    1---4;
    2---3;
    2---6;
    3---6;
    3---4;
    3---5;
    4---5;
```

# Interprétation des parcours

* Un graphe vu comme espace d'états (sommet: état, arête: action);
    * Labyrinthe;
    * Arbre des coups d'un jeu.

. . .

* BFS (Breadth-First) ou DFS (Depth-First) parcourent l'espace des états à la recherche du meilleur mouvement.
    * Les deux parcourent *tout* l'espace;
    * Mais si l'arbre est grand, l'espace est gigantesque!

. . .

* Quand on a un temps limité
    * BFS explore beaucoup de coups dans un futur proche;
    * DFS explore peu de coups dans un futur lointain.
+579 −0
Original line number Diff line number Diff line
---
title: "Graphes - Plus court chemin"
date: "2022-05-03"
patat:
    eval:
        tai:
            command: fish
            fragment: false
            replace: true
        ccc:
            command: fish
            fragment: false
            replace: true
    images:
      backend: auto
---

# Questions

* Qu'est-ce qu'un graphe? Un graphe orienté? Un graphe pondéré?

. . .

* Ensemble de sommets et arêtes, avec une direction, possédant une pondération.
* Comment représenter un graphe informatiquement?

. . .

* Liste ou matrice d'adjacence.
* Quels sont les deux parcours que nous avons vus?

. . .

* Parcours en largeur et profondeur.
* Donner l'idée générale des deux parcours.

# Illustration: plus courts chemins

![Illustration de plus court chemin de `s` à `t`.](figs/courts_chemin_intro.pdf)


# Plus courts chemins

## Contexte: les réseaux (informatique, transport, etc.)

* Graphe orienté;
* Source: sommet `s`;
* Destination: sommet `t`;
* Les arêtes ont des poids (coût d'utilisation, distance, etc.);
* Le coût d'un chemin est la somme des poids des arêtes d'un chemin.

## Problème à résoudre

* Quel est le plus court chemin entre `s` et `t`.

# Exemples d'application de plus court chemin

## Devenir riches!

* On part d'un tableau de taux de change entre devises.
* Quelle est la meilleure façon de convertir l'or en dollar?

![Taux de change.](figs/taux_change.pdf){width=80%}

. . .

* 1kg d'or => 327.25 dollars
* 1kg d'or => 208.1 livres => 327 dollars
* 1kg d'or => 455.2 francs => 304.39 euros => 327.28 dollars

# Exemples d'application de plus court chemin

## Formulation sous forme d'un graphe: Comment (3min)?

![Taux de change.](figs/taux_change.pdf){width=80%}


# Exemples d'application de plus court chemin

## Formulation sous forme d'un graphe: Comment (3min)?

![Graphes des taux de change.](figs/taux_change_graphe.pdf){width=60%}

* Un sommet par devise;
* Une arête orientée par transaction possible avec le poids égal au taux de change;
* Trouver le chemin qui maximise le produit des poids.

. . .

## Problème

* On aimerait plutôt avoir une somme...


# Exemples d'application de plus court chemin

## Conversion du problème en plus court chemin

* Soit `taux(u, v)` le taux de change entre la devise `u` et `v`.
* On pose `w(u,w)=-log(taux(u,v))`
* Trouver le chemin poids minimal pour les poids `w`.

![Graphe des taux de change avec logs.](figs/taux_change_graphe_log.pdf){width=60%}

* Cette conversion se base sur l'idée que

$$
\log(u\cdot v)=\log(u)+\log(v).
$$

# Applications de plus courts chemins

## Quelles applications voyez-vous?

. . .

* Déplacement d'un robot;
* Planificaiton de trajet / trafic urbain;
* Routage de télécommunications;
* Réseau électrique optimal;
* ...

# Plus courts chemins à source unique

* Soit un graphe, $G=(V, E)$, une fonction de pondération $w:E\rightarrow\mathbb{R}$, et un sommet $s\in V$
  * Trouver pour tout sommet $v\in V$, le chemin de poids minimal reliant $s$ à $v$.
* Algorithmes standards:
  * Dijkstra (arêtes de poids positif seulement);
  * Bellman-Ford (arêtes de poids positifs ou négatifs, mais sans cycles).
* Comment résoudre le problèmes si tous les poids sont les mêmes?

. . .

* Un parcours en largeur!

# Algorithme de Dijkstra

## Comment chercher pour un plus court chemin?

. . .

```
si distance(u,v) > distance(u,w) + distance(w,v)
    on passe par w plutôt qu'aller directement
```

# Algorithme de Dijkstra

## Idée générale

* On assigne à chaque noeud une distance $0$ pour $s$, $\infty$ pour les autres.
* Tous les noeuds sont marqués non-visités.
* Depuis du noeud courant, on suit chaque arête du noeud vers un sommet non visité et on calcule le poids du chemin à chaque voisin et on met à jour sa distance si elle est plus petite que la distance du noeud.
* Quand tous les voisins du noeud courant ont été visités, le noeud est mis à visité (il ne sera plus jamais visité).
* Continuer avec le noeud à la distance la plus faible.
* L'algorithme est terminé losrque le noeud de destination est marqué comme visité, ou qu'on a plus de noeuds qu'on peut visiter et que leur distance est infinie.

# Algorithme de Dijkstra

## Pseudo-code (5min, matrix)

. . .

```C
tab dijkstra(graph, s, t)
    pour chaque v dans graphe
        distance[v] = infini
        q = ajouter(q, v)
    distance[s] = 0
    tant que non_vide(q)
        u = min(q, distance) // plus petite distance dans q
        si u == t
            retourne distance
        q = remove(q, u)
        // voisin de u encore dans q
        pour chaque v dans voisinage(u, q) 
            n_distance = distance[u] + w(u, v)
            si n_distance < distance[v]
                distance[v] = n_distance
    retourne distance
```

# Algorithme de Dijkstra

* Cet algorithme, nous donne le plus court chemin mais...
* ne nous donne pas le chemin!

## Comment modifier l'algorithme pour avoir le chemin?

. . .

* Pour chaque nouveau noeud à visiter, il suffit d'enregistrer d'où on est venu!
* On a besoin d'un tableau `précédent`.

## Modifier le pseudo-code ci-dessus pour ce faire (3min matrix)

# Algorithme de Dijkstra

```C
tab, tab dijkstra(graph, s, t)
    pour chaque v dans graphe
        distance[v] = infini
        précédent[v] = indéfini
        q = ajouter(q, v)
    distance[s] = 0
    tant que non_vide(q)
        u = min(q, distance) // plus petite distance dans q
        si u == t
            retourne distance
        q = remove(q, u)
        // voisin de u encore dans q
        pour chaque v dans voisinage(u, q) 
            n_distance = distance[u] + w(u, v)
            si n_distance < distance[v]
                distance[v] = n_distance
                précédent[v] = u
    retourne distance, précédent
```

# Algorithme de Dijkstra

## Comment reconstruire un chemin ?

. . .

```C
pile parcours(précédent, s, t)
    sommets = vide
    u = t
    // on a atteint t ou on ne connait pas de chemin
    si u != s && précédent[u] != indéfini 
        tant que vrai 
            sommets = empiler(sommets, u)
            u = précédent[u]
            si u == s // la source est atteinte
                retourne sommets
    retourne sommets
```

# Algorithme de Dijkstra

::: columns

:::: column

![Initialisation.](figs/dijkstra_0.png)

::::

:::: column

. . .

![1 visité, `D[2]=1`, `D[4]=3`.](figs/dijkstra_1.png)

::::

:::

# Algorithme de Dijkstra

::: columns

:::: column

![Plus court est 2.](figs/dijkstra_1.png)


::::

:::: column

. . .

![2 visité, `D[3]=2`, `D[7]=3`.](figs/dijkstra_2.png)

::::

:::

# Algorithme de Dijkstra

::: columns

:::: column

![Plus court est 3.](figs/dijkstra_2.png)


::::

:::: column

. . .

![3 visité, `D[7]=3` inchangé, `D[6]=6`.](figs/dijkstra_3.png)

::::

:::

# Algorithme de Dijkstra


::: columns

:::: column

![Plus court est 4 ou 7.](figs/dijkstra_3.png)


::::

:::: column

. . .

![4 visité, `D[7]=3` inchangé, `D[5]=9`.](figs/dijkstra_4.png)

::::

:::

# Algorithme de Dijkstra

::: columns

:::: column

![Plus court est `7`.](figs/dijkstra_4.png)


::::

:::: column

. . .

![7 visité, `D[5]=7`, `D[6]=6` inchangé.](figs/dijkstra_5.png)

::::

:::

# Algorithme de Dijkstra

::: columns

:::: column

![Plus court est 6.](figs/dijkstra_5.png)


::::

:::: column

. . .

![`6` visité, `D[5]=7` inchangé.](figs/dijkstra_6.png)

::::

:::

# Algorithme de Dijkstra

::: columns

:::: column

![Plus court est 5 et c'est la cible.](figs/dijkstra_6.png)

::::

:::: column

. . .

![The end, tous les sommets ont été visités.](figs/dijkstra_7.png)

::::

:::

# Algorithme de Dijkstra amélioré

## On peut améliorer l'algorithme

* Avec une file de priorité!

## Une file de priorité est

* Une file dont chaque élément possède une priorité,
* Elle existe en deux saveurs: `min` ou `max`:
    * File `min`: les éléments les plus petits sont retirés en premier.
    * File `max`: les éléments les plus grands sont retirés en premier.
* On regarde l'implémentation de la `max`.

## Comment on fait ça?

. . .

* On insère les éléments à haute priorité tout devant dans la file!

# Les files de priorité

## Trois fonction principales

```C
booléen est_vide(élément) // triviale
élément enfiler(élément, data, priorité)
data défiler(élément)
rien modifier_priorité(élément, data, priotié)
nombre priorité(data) // utilitaire
```

## Pseudo-implémentation: structure (1min)

. . .

```C
struct élément
    data
    priorité
    élément suivant
```

# Les files de priorité

## Pseudo-implémentation: enfiler (2min)

. . .

```C
élément enfiler(élément, data, priorité)
    n_élément = créer_élément(data, priorité)
    si est_vide(élément)
        retourne n_élément
    si priorité(d) > priorité(e.d)
        n_élément.suivant = élément
        retourne n_élément
    sinon
        tmp = élément
        préc = élément
        tant que !est_vide(tmp) && priorité < tmp.priorité
            préc = tmp
            tmp = tmp.suivant
        prev.suivant = n_élément
        n_élément.suivant = tmp
        retourne élément           
```

# Les files de priorité

## Pseudo-implémentation: défiler (2min)

. . .

```C
data, élément défiler(élément)
    si est_vide(élément)
        retourne AARGL!
    sinon
        tmp = élément.data
        n_élément = élément.suivant
        libérer(élément)
        retourne tmp, n_élément
```

# Algorithme de Dijkstra avec file de priorité min

```C
distance, précédent dijkstra(graphe, s, t):
    distance[source] = 0
    fp = file_p_vide()
    pour v dans sommets(graphe)
        si v != s
            distance[v] = infini
            précédent[v] = indéfini
        fp = enfiler(fp, v, distance[v])
    tant que !est_vide(fp)
        u, fp = défiler(fp)
        pour v dans voisinage de u
            n_distance = distance[u] + w(u, v)
            si n_distance < distance[v]
                distance[v] = n_distance
                précédent[v] = u
                fp = changer_priorité(fp, v, n_distance)
    retourne distance, précédent
```

# Algorithme de Dijkstra avec file

\footnotesize

```C
distance dijkstra(graphe, s, t)
---------------------------------------------------------
    pour v dans sommets(graphe)
O(V)    si v != s
            distance[v] = infini
O(V)        fp = enfiler(fp, v, distance[v]) // notre impl est nulle
------------------O(V * V)-------------------------------
    tant que !est_vide(fp)
O(1)    u, fp = défiler(fp)
---------------------------------------------------------
O(E)    pour v dans voisinage de u
            n_distance = distance[u] + w(u, v)
            si n_distance < distance[v]
                distance[v] = n_distance
O(V)            fp = changer_priorité(fp, v, n_distance)
---------------------------------------------------------
    retourne distance
```

* Total: $\mathcal{O}(|V|^2+|E|\cdot |V|)$:
    * Graphe dense: $\mathcal{O}(|V|^3)$ 
    * Graphe peu dense: $\mathcal{O}(|V|^2)$ 

# Algorithme de Dijkstra avec file

## On peut faire mieux

* Avec une meilleure implémentation de la file de priorité:
    * Tas binaire: $\mathcal{O}(|V|\log|V|+|E|\log|V|)$.
    * Tas de Fibonnacci: $\mathcal{O}(|V|+|E|\log|V|)$
* Graphe dense: $\mathcal{O}(|V|^2\log|V|)$.
* Graphe peu dense: $\mathcal{O}(|V|\log|V|)$.

# Algorithme de Dijkstra (exercice, 5min) 

![L'exercice.](figs/dijkstra_exo.png){width=60%}

* Donner la liste de priorité, puis...

## A chaque étape donner:

* Le tableau des distances à `a`;
* Le tableau des prédécessueurs;
* L'état de la file de priorité.

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 1.](figs/dijkstra_ex_0.png)

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 2.](figs/dijkstra_ex_1.png)

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 3.](figs/dijkstra_ex_2.png)

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 4.](figs/dijkstra_ex_3.png)

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 5.](figs/dijkstra_ex_4.png)

# Algorithme de Dijkstra (corrigé) 

![Le corrigé partie 6.](figs/dijkstra_ex_5.png)

# Limitation de l'algorithme de Dijkstra

## Que se passe-t-il pour?

![Exemple.](figs/exemple_neg.png){width=50%}

## Quel est le problème?

. . .

* L'algorithme n'essaiera jamais le chemin `s->x->y->v` et prendra direct `s->v`.
* Ce problème n'apparaît que s'il y a des poids négatifs.
+776 −0

File added.

Preview size limit exceeded, changes collapsed.

+681 −0

File added.

Preview size limit exceeded, changes collapsed.

+14 −0
Original line number Diff line number Diff line
version: "3.3"
services:
    slides:
        #To use dockerfile : build: . 
        image:  omalaspinas/pandoc:latest
        environment:
            USER: 1000
            GROUP: 1000
        container_name: slides
        volumes:
            - ./:/data
        # entrypoint: ["make", "all"]
        working_dir: /data
        # user: "$(id -u):$(id -g)"
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="190.85277mm"
   height="40.306202mm"
   viewBox="0 0 190.85277 40.306201"
   version="1.1"
   id="svg5"
   inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
   sodipodi:docname="barbres_insert_easy_after.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview7"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="mm"
     showgrid="true"
     fit-margin-top="0"
     fit-margin-left="0"
     fit-margin-right="0"
     fit-margin-bottom="0"
     inkscape:zoom="0.83303"
     inkscape:cx="330.12017"
     inkscape:cy="214.278"
     inkscape:window-width="624"
     inkscape:window-height="1022"
     inkscape:window-x="1282"
     inkscape:window-y="44"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1">
    <inkscape:grid
       type="xygrid"
       id="grid824"
       originx="47.801382"
       originy="-79.198613" />
  </sodipodi:namedview>
  <defs
     id="defs2">
    <marker
       style="overflow:visible"
       id="Arrow2Lend"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-3"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-5" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-6"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-2" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-1"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-2" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-7"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-0" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-6"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-0" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-62"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-6" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-8"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-7" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-9"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-20" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-37"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-59" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-2"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-28" />
    </marker>
    <marker
       style="overflow:visible"
       id="DotL-36"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="DotL"
       inkscape:isstock="true">
      <path
         transform="matrix(0.8,0,0,0.8,5.92,0.8)"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
         d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
         id="path5653-1" />
    </marker>
    <marker
       style="overflow:visible"
       id="Arrow2Lend-29"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow2Lend"
       inkscape:isstock="true">
      <path
         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:0.625;stroke-linejoin:round"
         id="path5613-3" />
    </marker>
  </defs>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(47.801389,-79.198611)">
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none"
       id="rect848-3"
       width="26.458332"
       height="26.458332"
       x="-15.875"
       y="79.375" />
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none"
       id="rect848-6-5"
       width="26.458332"
       height="26.458332"
       x="15.875"
       y="79.375" />
    <text
       xml:space="preserve"
       style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;fill:#020000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-opacity:1"
       x="-4.995327"
       y="96.382408"
       id="text5839-6"><tspan
         sodipodi:role="line"
         id="tspan5837-2"
         style="fill:#020000;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-opacity:1"
         x="-4.995327"
         y="96.382408">1</tspan></text>
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-2"
       width="5.2916665"
       height="26.458332"
       x="10.583328"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-7-7"
       width="5.2916665"
       height="26.458332"
       x="-21.166668"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-5-0"
       width="5.2916665"
       height="26.458332"
       x="42.333344"
       y="79.375" />
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none"
       id="rect848-9"
       width="26.458332"
       height="26.458332"
       x="47.625004"
       y="79.375" />
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none"
       id="rect848-6-3"
       width="26.458332"
       height="26.458332"
       x="79.375"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-1"
       width="5.2916665"
       height="26.458332"
       x="74.083328"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-7-8"
       width="5.2916665"
       height="26.458332"
       x="42.333332"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-5-7"
       width="5.2916665"
       height="26.458332"
       x="105.83334"
       y="79.375" />
    <text
       xml:space="preserve"
       style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;stroke-width:0.264583"
       x="24.623627"
       y="96.382401"
       id="text17588"><tspan
         sodipodi:role="line"
         id="tspan17586"
         style="stroke-width:0.264583"
         x="24.623627"
         y="96.382401">3</tspan></text>
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:2.82222, 1.41111;stroke-dashoffset:0"
       id="rect848-9-9"
       width="26.458332"
       height="26.458332"
       x="111.125"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:2.82222, 1.41111;stroke-dashoffset:0;stroke-opacity:1"
       id="rect9240-1-3"
       width="5.2916665"
       height="26.458332"
       x="137.58333"
       y="79.375" />
    <rect
       style="fill:none;fill-opacity:1;stroke:#020000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect9240-7-8-7"
       width="5.2916665"
       height="26.458332"
       x="105.83333"
       y="79.375" />
    <text
       xml:space="preserve"
       style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.264583"
       x="89.545593"
       y="96.329491"
       id="text17588-9"><tspan
         sodipodi:role="line"
         id="tspan17586-2"
         style="fill:#000000;fill-opacity:1;stroke-width:0.264583"
         x="89.545593"
         y="96.329491">5</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.264583"
       x="57.822056"
       y="96.403572"
       id="text17588-9-7"><tspan
         sodipodi:role="line"
         id="tspan17586-2-5"
         style="fill:#000000;fill-opacity:1;stroke-width:0.264583"
         x="57.822056"
         y="96.403572">4</tspan></text>
    <rect
       style="fill:none;stroke:#000000;stroke-width:0.352777;stroke-miterlimit:4;stroke-dasharray:2.11666, 2.11666;stroke-dashoffset:0"
       id="rect848-6-3-2-0"
       width="26.458332"
       height="26.458332"
       x="-47.625"
       y="79.375008" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL);marker-end:url(#Arrow2Lend)"
       d="M -18.520838,92.604165 V 119.0625"
       id="path5590" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL-3);marker-end:url(#Arrow2Lend-6)"
       d="M 13.229162,92.604166 V 119.06251"
       id="path5590-9" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL-1);marker-end:url(#Arrow2Lend-7)"
       d="M 44.979162,92.604166 V 119.0625"
       id="path5590-93" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL-6);marker-end:url(#Arrow2Lend-62)"
       d="M 140.22916,92.604166 V 119.06251"
       id="path5590-1" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL-8);marker-end:url(#Arrow2Lend-9)"
       d="M 108.47916,92.604166 V 119.06251"
       id="path5590-2" />
    <path
       style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotL-37);marker-end:url(#Arrow2Lend-2)"
       d="M 76.729162,92.604159 V 119.0625"
       id="path5590-97" />
  </g>
</svg>