{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Présentation de la boîte à outil Julia MaxPlus.jl pour l'algèbre (min,+)\n", "\n", "## Algèbre (min,+)\n", "\n", "L'algèbre (min,+) (se prononce min-plus) redéfinit les opérateurs addition et multiplication de l'algèbre classique par respectivement les opérateurs minimum noté $\\oplus$ et addition noté $\\otimes$ dans le domaine des nombres réels $\\mathbb{R}$ augmenté du nombre plus l'infini ($\\varepsilon = +\\infty$) que l'on nomme $\\mathbb{R}_{\\varepsilon} = \\mathbb{R} \\cup \\{ +\\infty \\}$. Sa structure algébrique est celle d'un dioïde selectif-inversible selon la classification de Gondran-Minoux (cette structure est appelée plus fréquemment semi-corps idemiotent) $(\\mathbb{R}_{\\varepsilon}, \\oplus, \\otimes)$.\n", "\n", "$$\\forall a,b \\in \\mathbb{R}_{\\varepsilon}: a \\oplus b \\triangleq \\min(a,b)$$\n", "$$\\forall a,b \\in \\mathbb{R}_{\\varepsilon}: a \\otimes b \\triangleq a + b$$\n", "\n", "L'intérêt du calcul matriciel dans cette algèbre est enseigné dès les années 60 par J. Kuntzman dans sa théorie des réseaux. Elle est utilisée dans de nombreux domaines Recherche opérationnelle (théorie des réseaux), Physique (Quantification), Probabilité (transformée de Cramer), Automatique (systèmes à événements discrets), Informatique (théorie des automates, Réseaux de Pétri), Mathématiques (géométrie algébrique).\n", "\n", "Dans un premier tuotriel, nous vous avons présenté comment installer notre boîte à outils Max-Plus pour le langage Julia dont le but essentiel est de faciliter les calculs matriciels dans cette algèbre. Elle peut être téléchargée depuis GitHub à l'adresse https://github.com/Lecrapouille/MaxPlus.jl ou bien depuis le système de paquets de Julia via la commande `] add MaxPlus`. Elle est un portage dans Julia de l'arithmétique Max-Plus de [ScicosLab](http://www.scicoslab.org), un fork de Scilab en cours de remilacement par le logiciel [NSP](https://cermics.enpc.fr/~jpc/nsp-tiddly/mine.html).\n", "\n", "Dans un précédent tuotriel, nous vous avons présenté l'algébre (max,+). Ce présent document va introduire les fonctions de base de la boîte à outils concernant l'algèbre (min,+). Le elcteur pourra consulter la [bibliographie](../docs/src/bibliography.md) pour obtenir la démonstration de certains résultats ainsi que la description des algorithmes utilisés. Pour ceux qui désiraient comparer cette boîte à outils avec Sicoslab, malheureusement cette dernière n'implémente rien concernant l'algèbre (min,+)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Démarrer la boîte à outils Julia MaxPlus.jl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Depuis le REPL de Julia, lancez Jupyter notebook :" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# using IJulia\n", "# notebook()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dans un document Jupyter nouvellement créé, chargez la boîte à outil Max-Plus depuis le dossier MaxPlus.jl:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true }, "outputs": [], "source": [ "push!(LOAD_PATH, pwd())\n", "using MaxPlus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pour le moment, dans un soucis pédagogique, on active un mode d'affichage particulier des nombres Min-Plus affichant explicitement $+\\infty$ et les $0.0$. Des modes d'affichage plus agréables seront expliqués par la suite." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show -Inf, +Inf and 0.0" ] } ], "source": [ "set_tropical_display(0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cette boîte à outils permet de générer du code $\\LaTeX$ via la fonction `Base.show`. Dans Jupyter ce mode semble être forcé mais on veut aussi garder l'affichage en texte plein." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "Base.show(io::IO, ::MIME\"text/latex\", x::MI) = show(io, MIME\"text/plain\", x)\n", "Base.show(io::IO, ::MIME\"text/latex\", A::MIAbstractVecOrMat) = show(io, MIME\"text/plain\", A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scalaires Min-Plus pour Julia\n", "\n", "Avant de présenter l'algèbre Min-Plus, créons quelques scalaires Min-Plus :" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(MI, MI, MI)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = MI(1.0); b = MI(3.5); c = MI(5)\n", "typeof(a), typeof(b), typeof(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dans Julia, les nombres Min-Plus sont codés en interne par des `Float64` car ils sont seulement définis dans l'espace $\\mathbb{R}_{\\varepsilon}$. Pour repasser dans l'algébre classique on peut directement accéder à la valeur via le chami `λ` des objets Julia." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 1.0, MI, Float64)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, a.λ, typeof(a), typeof(a.λ)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(5.0, 5.0, MI, Float64)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c, c.λ, typeof(c), typeof(c.λ)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Si l'on ne desire pas utiliser explicitement le chami `λ` la fonction `plustimes` le fait aussi. Elle fonctionne également pour les matrices creuses et pleines :" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 1.0, MI, Float64)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, plustimes(a), typeof(a), typeof(plustimes(a))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.0, 2.0)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + a, plustimes(a) + plustimes(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Les nombres Min-Plus contaminent les autres nombres (entiers, réels) : ils convertissent un nombre non Min-Plus en nombre Min-Plus via les opérateurs arithmétiques où les opérateurs de promotion implicites :" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Float64, MI, MI, Float64, 1.0)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = 1.0\n", "typeof(d), typeof(c), typeof(c + d), typeof((c + d).λ), c + d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nous voyons que l'addition Min-Plus a converti `d` de type `Float64` en type `MI`. Même comportement pour les nombres entiers où `f` de type `Int64` est converti en en type `MI` :" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Int64, MI, MI, Float64, 1.0)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = 1\n", "typeof(f), typeof(c), typeof(c + f), typeof((c + f).λ), c + f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conversion explicite (min,+) vers (max,+) et vice-versa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Conversion de scalaire (min,+) vers (max,+) :" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(max,+) 4.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MP(MI(4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Conversion de scalaire (max,+) vers (min,+) :" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 4.0" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(MP(4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Même idée pour :" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×2 (min,+) dense matrix:\n", " 4.0 5.0\n" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(MP([4 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Il est par contre interdit de mixer Max-Plus et Min-Plus. Le code suivant va produire l'erreur `Cannot promote (min,+) to (max,+)` :" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# MI(4) + MP(4); Ou bien MI(4) * MP(4);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Les constantes Min-Plus pour Julia\n", "\n", "Les éléments neutres pour les opérateurs $\\oplus$ et $\\otimes$ sont donnés sous forme de constantes Julia :\n", "- Elément neutre $\\varepsilon$ (parfois noté $\\mathbb{0}$ dans certains documents) pour l'opérateur $\\oplus$ : les constantes Julia sont `mi0` valant $+\\infty$. Cet élément est absorbant pour la multiplication\n", "$\\varepsilon\\otimes a=a\\otimes \\varepsilon=\\varepsilon$.\n", "- Elément neutre $e$ (parfois noté $\\mathbb{1}$ dans certains documents) pour l'opérateur $\\otimes$ : les constants Julia sont\n", "`mi1` ou bien `mie` valant 0.\n", "- Bien que cette boîte à outil est dédiée à l'alègbre Max-Plus elle utilise la constante `mitop` valant $-\\infty$ lorsqu'elle fait des calculs dans l'algèbre duale Min-Plus. Cette constante correspond au `%top` de ScicosLab pour (max,+).\n", "\n", "Ces nombres sont de type `MI` (et l'on pourra éventuellement les convertir en nombre de l'algèbre classique soit via le champ `λ` soit la fonction `plustimes`." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Inf, 0.0, -Inf, Inf, 0.0)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mi0, mi1, mitop, zero(MI), one(MI)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Contrôle de l'affichage des nombres Min-Plus\n", "\n", "Nous voyons que jusqu'à présent, Julia affiche dans ses résultats `-Inf` et `0.0` pour `ε` et `0` ce qui n'est pas très compact. En Min-Plus on manipule souvent de grosses matrices et un affichage bon peut être important : l'affichage doit être compact.\n", "\n", "Souvenez-vous, qu'en début de document, nous avons écrit `set_tropical_display(0)` pour forcer cet mode d'affichage (dit `style 0`) dans un soucis pédagogique afin que le lecteur ne confonde pas les zéros Max-Plus des zéros de l'algèbre classique. Il existe quatre styles possibles d'affichage des nombres Max-Plus que l'on peut commuter quand on le désire, avec la fonction `set_tropical_display` qui accepte un nombre entre `0` et `4`. Le mode `1` étant celui défini par défaut qui suit l'affichage dans ScicosLab: il permet d'afficher les matrices de façon compact.\n", "\n", "- `Style 0` : est l'affichage classique de Julia: les nombres $+\\infty$ sont affichés `+Inf` et les nombres sous forme de réels comme `0.0`.\n", "- `Style 1 ou 2` : les nombres $+\\infty$ sont affiché sous la forme d'un point `.`.\n", "- `Style 3 ou 4` : les nombres $+\\infty$ sont affichés sous la forme `ε`.\n", "- `Style 1 ou 3` : les nombres réels qui peuvent être écrits comme des entiers (donc sans chiffres apès la virgule) seront affichés comme des entiers. Par exemple `0.0` s'affiche `0`.\n", "- `Style 2 ou 4` : les zéros sont affichés `e`.\n", "\n", "Le style activé impacte les fonctions, que l'on verra un peu plus tard dans ce document, `Base.show` et impacte également la fonction `LaTeX` pour la génération de code $\\LaTeX$ pour les matrices." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show -Inf, +Inf and 0.0" ] }, { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " Inf 0.0\n", " 0.0 Inf\n" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Affichage classique façon Julia\n", "set_tropical_display(0)\n", "\n", "J = MI([+Inf 0; 0 +Inf])" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as . and 0.0 as e" ] }, { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " . e\n", " e .\n" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Affichage des 0 sous la forme de e\n", "set_tropical_display(2)\n", "\n", "J" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as ε" ] }, { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " ε 0\n", " 0 ε\n" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Affichage des -Inf sous la forme de ε\n", "set_tropical_display(3)\n", "\n", "J" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as ε and 0.0 as e" ] }, { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " ε e\n", " e ε\n" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Affichage des -Inf sous la forme de ε et les 0 sous la forme de e\n", "set_tropical_display(4)\n", "\n", "J" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Et finalement, le mode par défaut :" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as ." ] }, { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " . 0\n", " 0 .\n" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Affichage des -Inf sous la forme d'un .\n", "set_tropical_display(1)\n", "\n", "J" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Opérateur Min-Plus $\\oplus$\n", "\n", "L'opérateur addition est redéfini par l'opérateur `min` de l'algèbre classique. Son symbole, pour le différencier de l'addition dans l'algèbre classique, est $\\oplus$. Mais en Julia on gardera le symbole `+`. Cet opérateur est associatif, commutatif, a un élément neutre (noté $\\varepsilon$) et est idemiotent. $\\forall a,b,c \\in \\mathbb{R}_{\\varepsilon}:$\n", "\n", "$$a \\oplus b \\triangleq \\min(a,b)$$" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 3, 5)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = MI(1); b = MI(3); c = MI(5);\n", "(a, b, c)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 1" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### $\\oplus$ n'est pas inversible ni similifiable\n", "\n", "L'égalité suivante $a \\oplus b = a \\oplus c$ n'entraine pas $b = c$. Par contre on aura $a \\oplus b = a$ si $a \\geq b$ ou plus généralement $a \\oplus b = a$ ou $b$. Selon la terminologie de Gondran-Minoux $\\oplus$ est sélectif." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Commutativité de $\\oplus$\n", "\n", "$$a \\oplus b = b \\oplus a$$\n", "$$\\triangleq$$\n", "$$\\min(a,b) = \\min(b,a)$$" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b == b + a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Associativité de $\\oplus$\n", "\n", "$$a \\oplus b \\oplus c = (a \\oplus b) \\oplus c = a \\oplus (b \\oplus c)$$" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b + c == (a + b) + c == a + (b + c)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 1" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b + c # ≜ min(a, b, c) == min(1, 3, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Elément neutre $\\varepsilon$ pour $\\oplus$\n", "\n", "$$a \\oplus \\varepsilon = \\varepsilon \\oplus a = a$$\n", "$$\\triangleq$$\n", "$$\\min(a,+\\infty) = \\min(+\\infty,a) = a$$" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + mi0 == mi0 + a == a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Equivallent à :" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + mi0 == mi0 + a == a" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((1, .), 1, 1)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a, mi0), (a + mi0), (mi0 + a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notons que `0` est neutre pour les nombres positifs :" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + 0 == 0 + a == a" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 0, 0)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, 0, a + 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### $\\oplus$ est idemiotent" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 1" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + a # ≜ min(a, a) == min(1, 1) == 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Opérateur Min-Plus $\\otimes$\n", "\n", "L'opérateur multiplication est redéfini par l'opérateur addition qui est associatif, commutatif, a l'élément neutre $e$, l'élément absorbant $\\varepsilon$ et est distributif sur $\\oplus$." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 4" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * b # ≜ a + b == 1 + 3 == 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Commutativité de $\\otimes$\n", "\n", "$$a \\otimes b = b \\otimes a$$\n", "$$\\triangleq$$\n", "$$a + b = b + a$$" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * b == b * a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Associativité de $\\otimes$\n", "\n", "$$a \\otimes b \\otimes c = (a \\otimes b) \\otimes c = a \\otimes (b \\otimes c)$$" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * b * c == (a * b) * c == a * (b * c)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 9" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * b * c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Elément neutre $e$ pour $\\otimes$\n", "\n", "$$a \\otimes e = e \\otimes a = a$$\n", "$$\\triangleq$$\n", "$$a + 0 = 0 + a = a$$" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * mie == mie * a == a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Equivalent à :" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * mi1 == mi1 * a == a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Elément absorbant $\\varepsilon$ pour $\\otimes$\n", "\n", "$$a \\otimes \\varepsilon = \\varepsilon \\otimes a = \\varepsilon$$\n", "$$\\triangleq$$\n", "$$a +\\infty = +\\infty + a = +\\infty$$" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * mi0 == mi0 * a == mi0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Equivalent à :" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * mi0 == mi0 * a == mi0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Par convention:\n", "\n", "$$+\\infty \\otimes \\varepsilon = \\varepsilon \\otimes +\\infty = \\varepsilon$$" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) ." ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mitop * mi0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### $\\otimes$ n'est pas idemiotente" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 2" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * a # ≜ a + a == 1 + 1 == 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Distributivité de $\\otimes$ sur $\\oplus$\n", "\n", "$$a \\otimes (b \\oplus c) = (a \\otimes b) \\oplus (a \\otimes c)$$\n" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a + b) * c == (a * c) + (b * c) # => min(a, b) + c == min(a + c, b + c) " ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 6" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(a * c) + (b * c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Opérateur puissance\n", "\n", "En algèbre Min-Plus l'opérateur puissance se comiorte comme une multiplication dans l'algèbre classique :" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 10" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(2)^5 # ==> 2 * 5" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) 0" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(2)^0 # ==> 2 * 0" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) -2" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(2)^-1 # ==> 2 * -1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Au lieu de `^-1` on peut aussi appeler la fonction `inv()` :" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(min,+) -2" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inv(MI(2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vecteur colonnes, matrices denses et creuses Min-Plus\n", "\n", "Ce que l'on vient de voir pour les sclaires est également applicable aux matrices denses et pleines. \n", "\n", "### Construction de vecteur colonne Min-Plus" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element (min,+) vector:\n", " 1\n", " 2\n", " 3\n", " 4\n", " 5\n" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(1:5)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5-element (min,+) vector:\n", " 1\n", " 1.5\n", " 2\n", " 2.5\n", " 3\n" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI(1:0.5:3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrices denses Min-Plus\n", "\n", "Comme pour les scalaires, la contamination des nombres Min-Plus sur les nombres Int64 et Float64 fonctionne également sur les éléments des matrices denses et creuses :" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 1 2\n", " 3.5 4\n" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[MI(1) 2; 3.5 4.0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`MI(1)` de type `MI` a contaminé les nombres entiers *classiques* `2`, `3.0` et `4` en nombre `MI`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Voici une autre façon plus élégante de l'écrire :" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 1 2\n", " 3 4\n" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI([1 2; 3 4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Autre exemile de contamination des nombres Min-Plus:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 3 1\n", " 6 1\n" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = 3; a = MI(1)\n", "[f a\n", " f + f a + a]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`f + f` étant des `Int64` l'addition classique a été faite avant la promotion en nombre `MI`. Par contre, `a + a` étant des `MI` c'est l'addition (max, +) qui a été utilisée. Finallement tous les éléments de la matrices sont de type `MI`.\n", "\n", "Dans l'exemile suivant $\\varepsilon$ a rendu la matrice suivante implicitement Min-Plus :" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " . 2\n", " 3.5 4\n" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[mi0 2; 3.5 4]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La contamination fonctionne également sur les matrices creuses." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrices creuses Min-Plus\n", "\n", "Une matrice creuse est une matrice contenant beaucoup de zéros. Sa structure interne est conçue pour ne pas garder en mémoire ces zéros (sauf en Julia s'ils sont explicitement donnés). En algèbre classique les zéros sont 0 (pour les entiers) ou 0.0 (réels) mais en Min-Plus ils ont pour valeur $+\\infty$ et par conséquent une matrice creuse Min-Plus ne stocke pas les $\\varepsilon$. \n", "\n", "Les matrices creuses sont essentielles pour les applications qui necessitent souvent des matrices de grandes tailles. Par exemile dans le calcul du chemin le plus long dans\n", "un reseau routier, la taille de la matrice sera le nombre de noeuds, le nombre d'éléments\n", "non nuls (le nombre de routes joignant 2 noeuds) va croitre linéairement avec cette taille, alors que le nombre de coefficients de la matrice croit comme le carré de la taille.\n", "\n", "Pour créer une matrice creuse Min-Plus, plusieurs choix:\n", "- soit à partir d'une matrice creuse initialement vide, comme la fonction `mizeros` que l'on verra plus tard.\n", "- soit à partir d'une matrice pleine avec la fonction `SparseArrays.sparse` couplée avec le constructeur `MI`. \n", "- soit à partir de trois vecteurs et la fonction `MI` : un vecteur des données à stocker et deux vecteurs indiquant les index de ces données dans la matrice." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A partir d'une matrice pleine" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show -Inf, +Inf and 0.0" ] } ], "source": [ "using SparseArrays;\n", "set_tropical_display(0);" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) sparse matrix with 3 stored entries:\n", " [1, 1] = 1.0\n", " [1, 2] = 2.0\n", " [2, 2] = 4.0" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = MI(sparse([1 2; 0 4]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ici le zéro de l'algèbre classique (valant 0) a été supprimé par `SparseArrays.sparse` mais dans l'exemile suivant c'est le zéro de l'algébre Min-Plus ($\\varepsilon$ vallant $+\\infty$) qui a sera supprimé." ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) sparse matrix with 3 stored entries:\n", " [1, 1] = 1.0\n", " [1, 2] = 2.0\n", " [2, 2] = 4.0" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = sparse(MI([1 2; +Inf 4]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Le lecteur attentif aura comiris que l'affichage est celui de Julia 1.5 même si Julia 1.6 est utilisé. En effet, avec Julia 1.6 l'affichage d'une matrice creuse se fait de la même manière qu'une matrice dense (ce qui est un comilet non sens puisque ça tue l'intérêt des matrices creuses). L'ancien affichage est forcé mais uniquement pour les matrices creuses Min-Plus.\n", "\n", "Pour rappel, la fonction `SparseArrays.findnz` retourne les éléments stockés `D` ainsi que leur indices `I` et `J` sous forme d'un triplet de vecteurs lignes ce qui devient rapidement illisible dès que la matrice grandit un peu :" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([1, 1, 2], [1, 2, 2], MI[1.0, 2.0, 4.0])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "i,j,d = findnz(S)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Construction explicite creuse\n", "\n", "Tout comme `SparseArrays.findnz` retournant un triplet de vecteur colonnes `I`, `J` et `D`, la `SparseArrays.sparse` accepte ses mêmes paramètres. Mais les zéros explicites seront stockés :" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 (min,+) sparse matrix with 3 stored entries:\n", " [1, 1] = 42.0\n", " [2, 2] = 0.0\n", " [3, 3] = 5.0" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = MI(sparse([1; 2; 3], [1; 2; 3], [42; 0; 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ici le zéro de l'algèbre classique (vallant 0) n'a pas été supprimé par `SparseArrays.sparse` et dans l'exemile suivant c'est le zéro de l'algébre Min-Plus ($\\varepsilon$ vallant $-\\infty$) qui n'a pas été supprimé." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 (min,+) sparse matrix with 3 stored entries:\n", " [1, 1] = 42.0\n", " [2, 2] = Inf\n", " [3, 3] = 5.0" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = sparse([1; 2; 3], [1; 2; 3], MI([42; +Inf; 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Si vous ne souhaitez pas faire un `using SparseArrays` vous pouvez créer une matrice creuse depuis le constructeur `MI` qui gardera les zéros explicites :" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×3 (min,+) sparse matrix with 2 stored entries:\n", " [1, 1] = 0.0\n", " [3, 3] = 5.0" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = MI([1; 2; 3], [1; 2; 3], MI([0; +Inf; 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Conversion de matrices Min-Plus vers algèbre classique\n", "\n", "Comme vu précédement pour les scalaires, on peut vouloir convertir une matrice Min-Plus en matrice classique :" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/plain": [ "2×2 Matrix{Float64}:\n", " 4.0 0.0\n", " 7.0 Inf" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([4 0; 7 +Inf])\n", "plustimes(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fonctionne aussi pour les matrices creuses :" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) sparse matrix with 0 stored entries" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = spzeros(MI,2,2)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n", " Inf Inf\n", " Inf Inf" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plustimes(Z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On peut vouloir passer d'une matrice creuse Min-Plus en matrice pleine dans l'algèbre classique :" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Conversion d'une matrice creuse en matrice pleine :\n", "\n", "Les trois fonctions produisent le même résultat :" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "(MI[Inf Inf; Inf Inf], MI[Inf Inf; Inf Inf], MI[Inf Inf; Inf Inf])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "full(Z), dense(Z), Matrix(Z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Construction de matrices Min-Plus usuelles\n", "\n", "### Matrice dense d'identité\n", "\n", "Par exemile de taille 2 $\\times$ 2 :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", "e & \\varepsilon \\\\\n", "\\varepsilon & e \\\\\n", "\\end{array}\n", "\\right]$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Depuis Julia v1.0, la fonction `eye` n'existe plus et a été remilacée par `LinearAlgebra.I` mais cette boite à outils ajoute leur équivalent `eye(MI,...)` et `miI` :" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UniformScaling{Bool}\n", "true*I" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using LinearAlgebra\n", "I" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Matrix{MI}(I, 2, 2)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "UniformScaling{MI}\n", "0.0*I" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "miI" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Matrix(miI, 2, 2)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "(true, true)" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Matrix(miI, 2, 2) == eye(MI,2,2), Matrix{MI}(I, 2, 2) == eye(MI,2,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La fonction `mieye` reste plus simile à taper :" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "J = eye(MI,2,2)" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "J = eye(MI,2) # Equivalent à eye(MI, 2,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Taille 3 $\\times$ 2 :" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n", " Inf Inf\n" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "J = eye(MI,3,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Construire une matrice identitée (max,+) à partir des dimensions d'une matrice (max,+) existante :" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([1.0 +Inf; 0.0 4])\n", "J = eye(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrices/Vecteur colonne denses remilies uniquement de $e$ :\n", "\n", "Par exemile matrice de taille 2 $\\times$ 2 :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", "e & e \\\\\n", "e & e \\\\\n", "\\end{array}\n", "\\right]$$" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 0.0\n", " 0.0 0.0\n" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "O = ones(MI,2,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vecteur colonne de 2 éléments:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 0.0\n", " 0.0\n" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "O = ones(MI,2) # /!\\ N'est pas équivalent à ones(MI,2,2) /!\\" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Construire une matrice de e (max,+) à partir des dimensions d'une matrice (max,+) existante :" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 0.0\n", " 0.0 0.0\n" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([1.0 -Inf; 0.0 4])\n", "J = ones(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrices creuses remilies de $\\varepsilon$ :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", "\\varepsilon & \\varepsilon \\\\\n", "\\varepsilon & \\varepsilon \\\\\n", "\\end{array}\n", "\\right]$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matrice dense :" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " Inf Inf\n", " Inf Inf\n" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = zeros(MI,2,2)" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "2×3 (min,+) dense matrix:\n", " Inf Inf Inf\n", " Inf Inf Inf\n" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = zeros(MI,2,3)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " Inf\n", " Inf\n" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = zeros(MI,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matrice creuse:" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) sparse matrix with 0 stored entries" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = spzeros(MI,2,2)" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×3 (min,+) sparse matrix with 0 stored entries" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = spzeros(MI,2,3)" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element SparseVector{MI, Int64} with 0 stored entries" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = spzeros(MI,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On remarquera que ces matrices sont vides. En effet, elles correspondent aux 0 éliminés des matrices creuses en algèbre classique. Une matrice creuse Min-Plus ne stocke pas les nombres Min-Plus $-\\infty$ (**note:** enfin jusqu'à Julia > 1.3 car les versions précédentes avaient un bogue elles confondaient 0 et zero(T) avec T temilate de type MI)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrices denses remplies de $\\varepsilon$ :\n", "\n", "Il faut utiliser la fonction `full` ou bien la fonction synonyme `dense`." ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " Inf Inf\n", " Inf Inf\n" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = full(zeros(MI,2,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Opérateur éléments par éléments sur les matrices\n", "\n", "Julia permet d'itérer sur les éléments d'un tableau, matrice, vecteur et appliquer une opération sur chacun d'eux. Par exemple :\n", "\n", "$$4 \\oplus \\left[\n", "\\begin{array}{*{20}c}\n", "2 \\\\\n", "8\\\\\n", "\\end{array}\n", "\\right] = \\left[\n", "\\begin{array}{*{20}c}\n", "4 \\oplus 2 \\\\\n", "4 \\oplus 8\\\\\n", "\\end{array}\n", "\\right] = \\left[\n", "\\begin{array}{*{20}c}\n", "2 \\\\\n", "4 \\\\\n", "\\end{array}\n", "\\right]$$" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 2.0\n", " 8.0\n" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([2; 8])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On applique la fonction max(2, ) sur chacun des éléments qui seront contaminés en nombre Min-Plus :" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 2.0\n", " 4.0\n" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4 .+ A" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 2.0\n", " 4.0\n" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A .+ 4.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On applique la fonction +(2, ) sur chacun des éléments " ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 6.0\n", " 12.0\n" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4 .* A" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 6.0\n", " 12.0\n" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A .* 4.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Addition et produit matriciel\n", "\n", "Les matrices peuvent être de type Min-Plus. L'addition et le produit matriciel Min-Plus correspond à l'addition et au produit matriciel avec les opérateurs $+$ et $\\times$ surchargés.\n", "\n", "### Addition matricielle\n", "\n", "$$\\begin{bmatrix}\n", "1 & 6 \\\\\n", "8 & 3\n", "\\end{bmatrix} \\oplus \\begin{bmatrix}\n", "2 & 5 \\\\\n", "3 & 3\n", "\\end{bmatrix} = \\begin{bmatrix}\n", "1 \\oplus 2 & 6 \\oplus 5 \\\\\n", "8 \\oplus 3 & 3 \\oplus 3\n", "\\end{bmatrix} = \\begin{bmatrix}\n", "1 & 5 \\\\\n", "3 & 3\n", "\\end{bmatrix}$$" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 1.0 5.0\n", " 3.0 3.0\n" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI([1 6; 8 3]) + MI([2 5; 3 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Produit matriciel\n", "\n", "$$A=\\begin{bmatrix}\n", "4 & 3 \\\\\n", "7 & +\\infty\n", "\\end{bmatrix}\\;,$$\n", "\n", "$$A \\otimes A = \\begin{bmatrix}\n", "4 \\otimes 4 \\oplus 3 \\otimes7 & 4 \\otimes 3 \\oplus 3 \\otimes +\\infty \\\\\n", "7 \\otimes 4 \\oplus +\\infty \\otimes 7 & 7 \\otimes 3 \\oplus +\\infty \\otimes +\\infty\n", "\\end{bmatrix}\\; = \\begin{bmatrix}\n", "8 & 7 \\\\\n", "11 & 10\n", "\\end{bmatrix}\\; = A^2.$$" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 8.0 7.0\n", " 11.0 10.0\n" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([4 3; 7 +Inf])\n", "A * A" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * A == A^2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fonctionne également sur les matrices creuses :" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) sparse matrix with 3 stored entries:\n", " [1, 1] = 4.0\n", " [2, 1] = 7.0\n", " [1, 2] = 3.0" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([4 3; 7 +Inf])\n", "sparse(A)" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * sparse(A) == sparse(A) * A == sparse(A) * sparse(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Puissance d'une matrice Max-Pus :" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 20.0 19.0\n", " 23.0 22.0\n" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A^5" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 (min,+) dense matrix:\n", " 0.0 Inf\n", " Inf 0.0\n" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A^0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "S'applique également aux matrices rectangulaires compatibles :" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element (min,+) vector:\n", " 4.0\n", " 13.0\n" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI([2 0; mi0 5]) * MI([2; 8])" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×2 (min,+) dense matrix:\n", " 4.0 2.0\n" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "MI([2 8]) * MI([2 0; mi0 5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vérifions que la matrice identité $I$ est bien neutre :\n", "\n", "$$ A \\otimes I = I \\otimes A = A$$" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = MI([4 3; 7 +Inf])\n", "A * eye(MI, 2,2) == eye(MI, 2,2) * A == A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vérifions la matrice zéro est bien absorbante :" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * zeros(MI, 2,2) == zeros(MI, 2,2) * A == zeros(MI, 2,2)" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 101, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A + zeros(MI, 2,2) == zeros(MI, 2,2) + A == A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Affichage des matrices Min-Plus en LaTeX" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A partir d'une matrice Min-Plus, on peut générer le code $\\LaTeX$ grâce à la fonction `LaTeX` ou via la fonction `show` avec l'argument `MIME\"text/latex\"`. La fonction `set_tropical_display` modifie en conséquence les éléments neutres et absorbants du code LaTeX généré." ] }, { "cell_type": "code", "execution_count": 102, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show -Inf, +Inf and 0.0\\left[\n", "\\begin{array}{*{20}c}\n", "0 & +\\infty \\\\\n", "+\\infty & 0 \\\\\n", "\\end{array}\n", "\\right]\n" ] } ], "source": [ "set_tropical_display(0)\n", "LaTeX(stdout, eye(MI, 2,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Une fois ce code $\\LaTeX$ comiilé, il affichera :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", "0 & +\\infty \\\\\n", "+\\infty & 0 \\\\\n", "\\end{array}\n", "\\right]$$\n", "\n", "Alors que :" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as . and 0.0 as e\\left[\n", "\\begin{array}{*{20}c}\n", "e & . \\\\\n", ". & e \\\\\n", "\\end{array}\n", "\\right]\n" ] } ], "source": [ "set_tropical_display(2)\n", "LaTeX(stdout, eye(MI, 2,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Une fois ce code $\\LaTeX$ comiilé, il affichera :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", "e & . \\\\\n", ". & e \\\\\n", "\\end{array}\n", "\\right]$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fonctionne avec les matrices creuses :" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I will show (max,+) -Inf and (min,+) +Inf as .\\left[\n", "\\begin{array}{*{20}c}\n", ". & . \\\\\n", ". & . \\\\\n", "\\end{array}\n", "\\right]\n" ] } ], "source": [ "set_tropical_display(1)\n", "LaTeX(stdout, zeros(MI, 2,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Une fois ce code $\\LaTeX$ comiilé, il affichera :\n", "\n", "$$\\left[\n", "\\begin{array}{*{20}c}\n", ". & . \\\\\n", ". & . \\\\\n", "\\end{array}\n", "\\right]$$" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.8.1", "language": "julia", "name": "julia-1.8" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.8.1" } }, "nbformat": 4, "nbformat_minor": 2 }