{"id":30,"date":"2018-11-27T22:59:22","date_gmt":"2018-11-27T21:59:22","guid":{"rendered":"http:\/\/pinkieduck.net\/?p=30"},"modified":"2019-02-22T22:54:23","modified_gmt":"2019-02-22T21:54:23","slug":"un-peu-de-topologie-en-coq","status":"publish","type":"post","link":"https:\/\/pinkieduck.net\/?p=30","title":{"rendered":"Un peu de topologie en Coq"},"content":{"rendered":"\n<p class=\"has-drop-cap\">Apprendre un langage de preuve est particuli\u00e8rement d\u00e9routant quand on est habitu\u00e9 aux langages de programmations \u00ab&nbsp;classiques&nbsp;\u00bb qu&rsquo;ils soient fonctionnels ou non&nbsp;: la plupart des patterns classiques deviennent perdent leur pertinence pour du code qui ne sera pas ex\u00e9cut\u00e9, et il faut adopter une fa\u00e7on diff\u00e9rente de \u00ab&nbsp;penser&nbsp;\u00bb qui s&rsquo;attachent aux propri\u00e9t\u00e9s des choses et non au comment de leur r\u00e9alisation. Cependant s&rsquo;il est difficile de transposer les pratiques de programmation pour s&rsquo;entrainer \u00e0 manipuler le langage, les maths fournissent beaucoup de mat\u00e9riau qui lui sied particuli\u00e8rement bien (ce qui n&rsquo;est pas surprenant). J&rsquo;ai choisi de m&rsquo;int\u00e9resser \u00e0 la topologie dans cette s\u00e9rie de billets pour voir jusqu&rsquo;o\u00f9 il est possible d&rsquo;aller. Je conseille fortement d&rsquo;avoir lu au moins le premier tome de software foundation pour bien profiter de cette s\u00e9rie.<\/p>\n\n\n\n<p>Pour l&rsquo;instant je m&rsquo;inspire librement de <a href=\"https:\/\/github.com\/coq-contribs\/topology\">https:\/\/github.com\/coq-contribs\/topology<\/a> et en particulier je vais utiliser comme lui le module <a href=\"https:\/\/github.com\/coq-contribs\/zorns-lemma\">https:\/\/github.com\/coq-contribs\/zorns-lemma<\/a> qui contient une impl\u00e9mentation des familles d\u00e9nombrables ou non d&rsquo;ensembles, de propri\u00e9t\u00e9s sur les fonctions etc. Il existe peut-\u00eatre d&rsquo;autres impl\u00e9mentation ailleurs mais je n&rsquo;en ai pas trouv\u00e9.<\/p>\n\n\n\n<h1>Installation<\/h1>\n\n\n\n<p>Afin de pouvoir utiliser simplement les modules coq public, j&rsquo;utilise le gestionnaire de paquets opam. Ce dernier n&rsquo;est pas disponible nativement sur Windows actuellement, il faut donc passer par Windows Subsystem for Linux. L&rsquo;installation se fait classiquement, via apt install m4 opam pour l&rsquo;image Debian ou Ubuntu, m4 s&rsquo;av\u00e9rant parfois requis par certains paquets opam.<\/p>\n\n\n\n<p>On utilise ensuite opam, qui va installer les paquets dans le r\u00e9pertoire de l&rsquo;utilisateur, et modifier le fichier profile pour que bash puisse trouver l&rsquo;ex\u00e9cutable Coq.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">opam init\nopam repo add coq-released http:\/\/coq.inria.fr\/opam\/released\nopam install coq<\/pre><\/pre>\n\n\n\n<h1>Un premier exercice <span style=\"font-size: 11pt;\"><br><\/span><\/h1>\n\n\n\n<p>Pour d\u00e9buter, j&rsquo;ai pr\u00e9f\u00e9r\u00e9 rester modeste en choisissant un exercice relativement \u00ab&nbsp;tautologique&nbsp;\u00bb de topologie classique, trouv\u00e9 sur cette liste&nbsp;: <a href=\"http:\/\/math.univ-lille1.fr\/~bodin\/exolic1\/exolic.pdf\">http:\/\/math.univ-lille1.fr\/~bodin\/exolic1\/exolic.pdf<\/a> :<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Soit \\(X\\) un espace topologique, et \\(f\\) une application quelconque de \\(X\\) dans un ensemble \\(Y\\). On dit qu&rsquo;une partie \\(A\\) de \\(Y\\) est ouverte, si \\(f^{\u2212 1}(A)\\) est un ouvert de \\(X\\). V\u00e9rifier qu&rsquo;on a d\u00e9fini ainsi une topologie sur \\(Y\\).<\/p><\/blockquote>\n\n\n\n<p>Sur les 3 axiomes d\u00e9finissant une topologie, celui sur l&rsquo;appartenance de l&rsquo;ensemble vide et de Y est relativement \u00e9vident <\/p>\n\n\n<span id='easy-footnote-1-30' class='easy-footnote-margin-adjust'><\/span><span class='easy-footnote'><a href='https:\/\/pinkieduck.net\/?p=30#easy-footnote-bottom-1-30' title='&lt;span style=&quot;color: #404040;&quot;&gt;surtout parce que je n&amp;rsquo;ai pas envie de trop m&amp;rsquo;attarder dessus'><sup>1<\/sup><\/a><\/span>\n\n\n\n<p>, celui sur l&rsquo;intersection fini est d\u00e9j\u00e0 d\u00e9fini dans zorns-lemma. Il reste donc l&rsquo;axiome de stabilit\u00e9 par union.<\/p>\n\n\n\n<h2><span style=\"color: #5a5a5a;\">D\u00e9finitions d&rsquo;ensemble, de r\u00e9union quelconque etc<br><\/span><\/h2>\n\n\n\n<p>La librairie standard de Coq propose une impl\u00e9mentation des ensembles <a href=\"https:\/\/coq.inria.fr\/library\/Coq.Sets.Ensembles.html\">https:\/\/coq.inria.fr\/library\/Coq.Sets.Ensembles.html<\/a>&nbsp;: ces derniers contiennent juste une fonction d&rsquo;appartenance de leur \u00e9l\u00e9ment. On notera surtout la pr\u00e9sence de l&rsquo;axiome d&rsquo;extensionalit\u00e9 (deux ensembles sont \u00e9gaux s&rsquo;ils sont inclus l&rsquo;un dans l&rsquo;autre) qu&rsquo;on va utiliser dans la suite.<\/p>\n\n\n\n<p>Cot\u00e9 zorns-lemma existe une d\u00e9finition de famille d&rsquo;ensembles <a href=\"https:\/\/github.com\/coq-contribs\/zorns-lemma\/blob\/master\/Families.v\">https:\/\/github.com\/coq-contribs\/zorns-lemma\/blob\/master\/Families.v<\/a>, qui correspond, de fa\u00e7on plut\u00f4t pr\u00e9visible, \u00e0 un alias sur les ensembles d&rsquo;ensembles. Le type qui nous int\u00e9resse en particulier est celui de FamilyUnion, qui va \u00ab\u00a0r\u00e9duire\u00a0\u00bb une famille en un ensemble. A noter que zorns-lemma propose aussi une version \u00ab\u00a0indexed\u00a0\u00bb des familles, version indexed qui, contrairement \u00e0 ce que je pensais initialement, peut \u00eatre index\u00e9e par n&rsquo;importe quoi, et pas seulement par des entiers, et est probablement plus simple \u00e0 manipuler\u00a0; cependant, dans la suite, je me base seulement sur le FamilyUnion classique.<\/p>\n\n\n\n<h2>On se lance<\/h2>\n\n\n\n<p>Premier point : d\u00e9finir l&rsquo;ensemble r\u00e9ciproque d&rsquo;une fonction. On pourrait certes utiliser la d\u00e9finition fournie par zorns-lemma, mais, vu que ce module ne fournit que tr\u00e8s peu de propri\u00e9t\u00e9s sur les fonctions r\u00e9ciproques, le gain est minime.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">From Topology Require Import TopologicalSpaces.\n\nDefinition img_recip (X Y:Type) (f:X-&amp;amp;gt;Y) (A: Ensemble Y) : Ensemble X:=\n\nfun x =&amp;amp;gt; In A (f x).<\/pre><\/pre>\n\n\n\n<p>Seconde \u00e9tape, formuler l&rsquo;\u00e9galit\u00e9 de l&rsquo;union des images r\u00e9ciproques et de l&rsquo;image r\u00e9ciproque de l&rsquo;union. Pour plus de lisibilit\u00e9, on va d\u00e9finir les deux s\u00e9par\u00e9ment. D&rsquo;un cot\u00e9, on a l&rsquo;image r\u00e9ciproque d&rsquo;une union, relativement imm\u00e9diate\u00a0:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">Definition img_recip_union (X Y:Type) (Fa: Family Y) (f:X-&amp;amp;gt;Y) :=\n\nimg_recip X Y f (FamilyUnion Fa).<\/pre><\/pre>\n\n\n\n<p>De l&rsquo;autre, on a la r\u00e9union des images r\u00e9ciproques, et c&rsquo;est l\u00e0 o\u00f9 les choses commencent \u00e0 se g\u00e2ter. Si une FamilyUnion est une ensemble en premier lieu, il faut donc \u00e9crire une fonction d&rsquo;appartenance, sauf que les \u00e9l\u00e9ments sont ici eux-m\u00eames des ensembles\u2026dont la description n\u00e9cessite quelques circonvolutions\u00a0: il faut \u00e0 la fois exprimer qu&rsquo;on a l&rsquo;image r\u00e9ciproque de quelque chose, et que ledit quelque chose est dans la famille de d\u00e9part. J&rsquo;avoue avoir gal\u00e9r\u00e9 quelques temps avant de parvenir \u00e0 \u00e9crire la d\u00e9finition, dont l&rsquo;in\u00e9l\u00e9gance augure quelques prises de t\u00eate dans les futures preuves qui y seront rattach\u00e9es\u00a0:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">Definition img_recip_union_as_fu (X Y:Type) (Fa: Family Y) (f:X-&amp;amp;gt;Y) : Ensemble X :=\n\nFamilyUnion (fun S =&amp;amp;gt; exists F, In Fa F \/\\ S = (img_recip X Y f F)).<\/pre><\/pre>\n\n\n\n<p>Il aurait probablement \u00e9t\u00e9 plus simple de passer par les familles index\u00e9es (la facult\u00e9 de \u00ab&nbsp;nommer&nbsp;\u00bb les ensembles qu&rsquo;on manipule par leurs indices plut\u00f4t que par un quantifieur d&rsquo;existence doit plut\u00f4t aider).<\/p>\n\n\n\n<p>On pose enfin le th\u00e9or\u00e8me d&rsquo;\u00e9galit\u00e9 des deux quantit\u00e9s&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">Theorem union_img_inverse : forall (X Y : Type) (Fa:Family Y) (f:X-&amp;amp;gt;Y),\n\n(img_recip_union_as_fu X Y Fa f) = (img_recip_union X Y Fa f).\n\nProof.<\/pre><\/pre>\n\n\n\n<p>Comme \u00e9nonc\u00e9 pr\u00e9alablement, on reste sur un exercice plut\u00f4t tautologique, o\u00f9 on ne fait gu\u00e8re que renommer les choses. Par cons\u00e9quent une grosse partie de la preuve va consister \u00e0 utiliser en boucle la tactique unfold, qui va juste expliciter les d\u00e9finitions\u00a0:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">unfold img_recip_union_as_fu. unfold img_recip_union.\n\nintros. unfold img_recip. unfold In.<\/pre><\/pre>\n\n\n\n<p>On se retrouve avec une \u00e9galit\u00e9 entre deux ensembles.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">apply Extensionality_Ensembles. split.\n\n- unfold Included. unfold In. intros. destruct H eqn:Heqn. unfold In in i. destruct i eqn:ieqn. destruct a.\n\napply family_union_intro with (S:=x0). subst. apply f0. unfold In in i0. unfold In. subst. apply i0.\n\n- unfold Included. intros. unfold In in H. Print FamilyUnion. remember (f x) as fx. destruct H.\n\neapply family_union_intro with (S:=fun x1 : X =&amp;amp;gt; S (f x1)). unfold In. exists S. split. apply H. trivial.\n\nunfold In. rewrite &amp;amp;lt;- Heqfx. apply H0.\n\nQed.<\/pre><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Apprendre un langage de preuve est particuli\u00e8rement d\u00e9routant quand on est habitu\u00e9 aux langages de programmations \u00ab&nbsp;classiques&nbsp;\u00bb qu&rsquo;ils soient fonctionnels ou non&nbsp;: la plupart des patterns classiques deviennent perdent leur pertinence pour du code qui ne sera pas ex\u00e9cut\u00e9, et il faut adopter une fa\u00e7on diff\u00e9rente de \u00ab&nbsp;penser&nbsp;\u00bb qui s&rsquo;attachent aux propri\u00e9t\u00e9s des choses et [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/posts\/30"}],"collection":[{"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=30"}],"version-history":[{"count":16,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/posts\/30\/revisions"}],"predecessor-version":[{"id":109,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=\/wp\/v2\/posts\/30\/revisions\/109"}],"wp:attachment":[{"href":"https:\/\/pinkieduck.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=30"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=30"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pinkieduck.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=30"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}