CoursTuring


Algorithmes ? Programmation ?

Ils sont absolument partout dans votre quotidien.

Venez découvrir comment...




Avez-vous déjà passé des heures à regarder des vidéos en vous demandant comment la prochaine proposée est toujours plus captivante que la précédente ? Vous êtes-vous déjà demandé comment votre téléphone portable trouve le plus court chemin pour rentrer chez vous ? Ou peut-être aimez-vous simplement résoudre des énigmes et comprendre comment les choses fonctionnent ? Si oui, ce cours est pour vous : nous parlerons des algorithmes clés qui sont à la base de nos technologies modernes, en partant des fondements mathématiques jusqu’à leur implémentation concrète.



Public cible : élèves du gymnase (école de maturité, école de commerce, école de culture générale), 15-18 ans.



Pré-requis : une curiosité naturelle pour ces questions, une première expérience avec la programmation et le désir d’en apprendre plus.

Inscription

 Lien de pré-inscription

La période pour les pré-inscriptions s'étend du 1er avril au 30 juin 2025. Veuillez trouver ici le lien pour cette pré-inscription. Vous serez informé·e·s de votre inscription définitive d’ici au 15 juillet 2025. Afin de confirmer celle-ci, il vous sera alors demandé de régler 50.- de frais liés à ce cours.

Horaire et lieux des cours : les cours sont donnés les samedis matin de 9h à 12h en salles CO 020 et CO 023.

Programme

Séance d'introduction

Rendez-vous pour cette première séance le samedi 30 août à 10h, en salle BC 420.

Programme:

- Présentation du Cours Turing par Michael Kapralov et Olivier Lévêque

- Exposé de Sabine Süsstrunk, doyenne de la Faculté Informatique et Communication

La séance sera suivie d'un apéritif de bienvenue.

			

Année 1, Module 1 : Programmation (Romain Edelmann)

Ce module d’introduction à Python vous apprendra à comprendre, analyser et concevoir des programmes simples de manière autonome et efficace.

Grâce à un mélange de cours théoriques, d’exercices pratiques et de projets, vous découvrirez les bases du langage Python tout en développant votre logique algorithmique.

Des notions clés d’ingénierie logicielle viendront aussi enrichir votre apprentissage.

Le module se terminera par un projet final de conception et résolution de labyrinthes.

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 020.
6 septembre 2025
13 septembre 2025
20 septembre 2025
27 septembre 2025
4 octobre 2025
1er novembre 2025
8 novembre 2025
15 novembre 2025
(notes de cours à suivre)

Année 1, Module 2 : Cryptographie (Olivier Lévêque)

Dans ce cours, nous passerons tout d'abord en revue quelques systèmes de chiffrement historiques, du chiffre de César jusqu'au chiffrement de la machine Enigma utilisée pendant la seconde guerre mondiale.

Puis nous parlerons des systèmes plus modernes que sont les systèmes DES et AES, et aussi des sytèmes de chiffrement dits "à clé publique" datant des années 70, qui ont induit une véritable révolution dans le monde de la cryptographie. Parmi ces sytèmes, nous verrons notamment le célèbre protocole RSA (du nom de ses inventeurs Rivest, Shamir et Adleman) utilisé actuellement pour la majorité des transactions sur internet.

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 020.
22 novembre 2025
29 novembre 2025
6 décembre 2025
10 janvier 2026
17 janvier 2026
24 janvier 2026
31 janvier 2026
7 février 2026
Notes de cours (version du 18 août 2025)

Année 1, Module 3 : Traitement d'images (Joachim Hugonot)

Notre manière d'utiliser les images a évolué de manière considérable ces dernières années. Tout le monde est aujourd'hui capable de prendre des photos, de les modifier, de les partager et de les utiliser dans une multitude de contextes. Les images contiennent énormément d'informations et nous verrons comment il est possible de les analyser automatiquement grâce à des algorithmes.

Nous commencerons par découvrir comment manipuler les images avec Python, puis nous découvrirons une sélection de méthodes célèbres d'analyse d'images. Finalement, nous aborderons le thème des réseaux de neurones afin de comprendre comment ils fonctionnent, comment les entrainer et comment ils ont révolutionné le domaine de l'analyse d'images et notre société.

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 020.
28 février 2026
7 mars 2026
14 mars 2026
21 mars 2026
28 mars 2026
25 avril 2026
2 mai 2026
9 mai 2026
(note de cours à suivre)

Intermezzo

Mini-compétition rassemblant toutes les volées du cours Turing, en salle INF 3.
13 décembre 2025

Année 2, Module 1 : Génie logiciel (Solal Pirelli)

Pour développer un logiciel, il faut plus que simplement écrire du code. Un logiciel doit au minimum être correct, suffisament rapide, et suffisament facile à maintenir pour garantir son évolution.

Comment s'assurer que son code marche non seulement dans les cas simples, mais aussi par exemple si un serveur utilisé retourne une erreur rare ?

Comment vérifier que son code continue à fonctionner rapidement même en gérant beaucoup de données, sans devoir le tester à la main à chaque changement ?

Comment développer un logiciel à plusieurs en "open source", en gardant une trace des changements et en acceptant les contributions de personnes à l'autre bout du monde ?

Le module Génie Logiciel répondra à ces questions et plus encore.

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 023.
6 septembre 2025
13 septembre 2025
20 septembre 2025
27 septembre 2025
4 octobre 2025
1er novembre 2025
8 novembre 2025
15 novembre 2025
(notes de cours à suivre)

Année 2, Module 2 : Programmation fonctionnelle (Pierre Quinton)

Lorsque l'on développe, prendre le temps de concevoir la structure avant de coder est une étape cruciale. Certes, cela peut sembler ralentir le démarrage, mais chaque composant développé par la suite devient significativement plus simple et rapide à implémenter. Sauf pour les projets à très court terme, c'est généralement un investissement très rentable.

Un code bien structuré, découpé en fonctions et classes aux rôles clairement définis et aux implémentations concises, est toujours une bonne pratique. Cette approche permet une meilleure maîtrise du comportement du programme et aide à prévenir les erreurs.

La programmation fonctionnelle offre un ensemble d'outils et de principes puissants qui facilitent la prise de décisions éclairées en matière de conception logicielle.

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 023.
22 novembre 2025
29 novembre 2025
6 décembre 2025
10 janvier 2026
17 janvier 2026
24 janvier 2026
31 janvier 2026
7 février 2026
(notes de cours à suivre)

Année 2, Module 3 : Optimisation combinatoire (Cédric Donner)

Dans ce cours, nous allons résoudre des problèmes dits de “satisfaction de contraintes” ou “d’optimisation sous contraintes” à l’aide de différentes techniques algorithmiques. Nous commencerons par des approches naïves que nous raffinerons ensuite pour les optimiser. Nous allons en particulier aborder un paradigme de programmation fascinant, la programmation par contraintes. Cette manière de programmer est née de la bonne vieille intelligence artificielle des années 1980-2010. Elle consiste à décrire des problèmes de satisfaction de contraintes (par exemple la résolution de Sudoku) sous forme déclarative et laisser l’ordinateur trouver la solution en expérimentant différentes stratégies et approches de résolution (heuristiques).

Les cours sont donnés les samedis matin de 9h à 12h en salle CO 023.
28 février 2026
7 mars 2026
14 mars 2026
21 mars 2026
28 mars 2026
25 avril 2026
2 mai 2026
9 mai 2026
(notes de cours à suivre)

Cérémonie de clôture

(description à suivre)
30 mai 2026

Équipe pédagogique


import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Michael Kapralov
Direction Scientifique
Mikhail Kapralov est un spécialiste de l’informatique théorique. Ses recherches sur les algorithmes sublinéaires ont abouti à des percées majeures dans les secteurs du big data et de l’analyse des données. Mikhail Kapralov a reçu plusieurs prix, dont une bourse ERC Starting Grant en 2017. Alors que ses travaux sont de nature théorique, il entretient néanmoins des liens forts avec l’industrie. Ses contacts avec des partenaires industriels comme le Microsoft Research Lab et Google Research ouvrent des perspectives professionnelles inédites à ses étudiantes et étudiants.
<span style="color:red">import numpy as np</span><br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Romain Edelmann
Enseignant
Romain Edelmann enseigne l'informatique au Gymnase de Burier, là-même où il avait obtenu sa maturité et découvert sa passion pour l'informatique. Sa maturité en poche, Romain a décidé d'étudier à l'EPFL et y a obtenu un bachelor, un master et finalement un doctorat en informatique.

Durant ses études, Romain a largement profité des nombreuses occasions de partir à l'étranger. Il a notamment passé une année à l'université nationale de Singapour et 6 mois à Google Zurich. Depuis la fin de ses études, Romain a été très actif dans l'enseignement de l'informatique. Récemment, il a été impliqué dans la création de ressources pour l'enseignement de l'informatique au gymnase et donne des Summer Schools à l'EPFL pour les gymnasiens.
import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Olivier Lévêque
Enseignant
Olivier Lévêque est maître d’enseignement et de recherche à la Faculté Informatique et Communications de l’EPFL. Ayant d’abord obtenu son diplôme de physique à l’EPFL en 1995, puis soutenu sa thèse en mathématiques en 2001, toujours à l’EPFL, il a ensuite rejoint la Faculté Informatique et Communications. Son domaine de spécialisation est celui des probabilités: pendant sa thèse, il a travaillé plus spécifiquement sur les équations aux dérivées partielles stochastiques, et depuis son arrivée à la Facuilté I&C, il s’est intéressé plus particulièrement à la théorie des matrices aléatoires, ainsi qu’à ses nombreuses applications.

D’autre part, Olivier s’est beaucoup investi ces dernières années dans la formation des enseignants d’informatique au gymnase (avec le programme GymInf, notamment) pour préparer l’arrivée de la nouvelle discipline obligatoire.
import numpy as np<br />
import matplotlib.pyplot as pl<br />
<br />
# ============ define relevant functions =============<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
def apply_laplacian(mat):<br />
    """This function applies a discretized Laplacian<br />
    in periodic boundary conditions to a matrix<br />
    For more information see<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
    """<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
    # the total difference<br />
    neigh_mat = -4*mat.copy()<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
    # the discrete difference formula<br />
    neighbors = [<br />
                    ( 1.0,  (-1, 0) ),<br />
                    ( 1.0,  ( 0,-1) ),<br />
                    ( 1.0,  ( 0, 1) ),<br />
                    ( 1.0,  ( 1, 0) ),<br />
                ]<br />
<br />
    # shift matrix according to demanded neighbors<br />
    # and add to this cell with corresponding weight<br />
    for weight, neigh in neighbors:<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
    return neigh_mat<br />
<br />
# Define the update formula for chemicals A and B<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
    # compute the diffusion part of the update<br />
    diff_A = DA * apply_laplacian(A)<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
    # Apply chemical reaction<br />
    reaction = A*B**2<br />
    diff_A -= reaction<br />
    diff_B += reaction<br />
<br />
    # Apply birth/death<br />
    diff_A += f * (1-A)<br />
    diff_B -= (k+f) * B<br />
<br />
    A += diff_A * delta_t<br />
    B += diff_B * delta_t<br />
<br />
    return A, B<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
    """get the initial chemical concentrations"""<br />
<br />
    # get initial homogeneous concentrations<br />
    A = (1-random_influence) * np.ones((N,N))<br />
    B = np.zeros((N,N))<br />
<br />
    # put some noise on there<br />
    A += random_influence * np.random.random((N,N))<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
    # get center and radius for initial disturbance<br />
    N2, r = N//2, 50<br />
<br />
    # apply initial disturbance<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
    return A, B<br />
<br />
def draw(A, B):<br />
    """return the matplotlib artists for animation"""<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
    ax[0].axis('off')<br />
    ax[1].axis('off')<br />
    ax[0].set_title('A')<br />
    ax[1].set_title('B')<br />
<br />
    return fig, imA, imB<br />
<br />
# =========== define model parameters ==========<br />
<br />
# update in time<br />
delta_t = 1.0<br />
<br />
# Diffusion coefficients<br />
DA = 0.16<br />
DB = 0.08<br />
<br />
# define birth/death rates<br />
f = 0.060<br />
k = 0.062<br />
<br />
# grid size<br />
N = 200<br />
<br />
# intialize the chemical concentrations<br />
A, B = get_initial_A_and_B(N)<br />
<br />
N_simulation_steps = 10000<br />
for step in range(N_simulation_steps):<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
draw(A, B)<br />
<br />
# show the result<br />
pl.show()<br />

Joachim Hugonot
Enseignant
Joachim Hugonot est enseignant d'informatique au gymnase de Renens. Il a obtenu son master et son bachelor en informatique à l'EPFL et a travaillé pendant 5 ans comme ingénieur de recherche dans deux laboratoires de l'EPFL. Joachim est passionné par l'intelligence artificielle, les réseaux de neurones, les modèles génératifs et la façon dont ces algorithmes se sont insinués dans nos vies. Il a pour volonté de développer la pensée critique, la curiosité et la prise de conscience chez ses élèves quant aux enjeux de société liés à l’informatique.
import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Cédric Donner
Enseignant
Cédric Donner enseigne l’informatique au Collège du Sud (Gymnase), à Bulle, où il a obtenu sa maturité et développé sa passion pour l’informatique. Il a ensuite débuté des études d’informatique / physique à l’Université de Fribourg, pour bifurquer ensuite en mathématiques et y obtenir son master en 2008.

Déjà bien avant l’introduction de l’informatique comme discipline obligatoire au gymnase, Cédric a été très actif dans le développement de ressources pédagogiques d’enseignement de l’informatique, dans le cadre de son enseignement, du TJGroup et l'ETHZ. Il a contribué à la traduction et à la rédaction de plusieurs ouvrages pédagogiques pour l’école obligatoire et le gymnase. Actuellement, il contribue au développement d’outils et environnements d’apprentissage de l’informatique, notamment le nouvel IDE WebTigerPython, successeur de TigerJython.
import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Solal Pirelli
Enseignant
Solal Pirelli est chercheur en systèmes informatiques et méthodes formelles.
Il a obtenu son bachelor, master, et doctorat en informatique à l'EPFL, se spécialisant dans la vérification automatisée de logiciels réseaux comme les pare-feux.

À l'EPFL, il a co-enseigné les cours de Génie Logiciel et de Projet de Développement Logiciel, permettant aux étudiants de dépasser la simple écriture de code pour comprendre comment planifier, développer, et maintenir un produit logiciel.
Il a également organisé des évènements tels que le Helvetic Coding Contest, plus grand concours suisse de programmation, et LauzHack, un hackathon par et pour des étudiants.
import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Pierre Quinton
Enseignant
Pierre Quinton est chercheur et développeur passionné par l'informatique et les mathématiques. Il a obtenu son baccalauréat à Toulouse, puis a poursuivi ses études en informatique avec un Bachelor, suivi d'un Master en Data Science à l'EPFL. Son parcours l'a ensuite mené au Danemark, où il a effectué un stage chez B&O. Par la suite, il est retourné à l'EPFL pour y réaliser un doctorat en théorie de l'information.

Ses recherches se concentrent sur un large éventail de domaines, notamment la théorie de l'information, la théorie des probabilités, la théorie de la mesure, la théorie de l'ordre et l'optimisation multi-objective. En parallèle de ses activités de recherche, il est le développeur et le mainteneur de TorchJD (https://github.com/TorchJD/torchjd), une bibliothèque Python qui permet de faire de l'optimisation multi-objective basée sur PyTorch.
import numpy as np<br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Jennyfer Steiner
Assistante
Jennyfer est en 3ème année de Bachelor de Systèmes de Communication à l'EPFL et a notamment pu enseigner dans les cours "Internet et code pour les filles" ainsi que "Toi aussi crée ton appli" proposés par l'EPFL.
<span style="color:red">import numpy as np</span><br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Ernest Guisset
Assistant
Ernest Guisset est étudiant en master de mathématiques de l'EPFL, avec un intérêt particulier pour l'informatique. Il a fait auparavant du volontariat dans un Coding Club, où il enseignait la programmation à des enfants très jeunes. Il a aussi participé à l'enseignement de la "Semaine Théorie des jeux & IA." Il vient de Bruxelles, où il a effectué son bachelor.
<span style="color:red">import numpy as np</span><br />
<br />
import matplotlib.pyplot as pl<br />
<br />
<br />
<br />
# ============ define relevant functions =============<br />
<br />
<br />
<br />
# an efficient function to compute a mean over neighboring cells<br />
<br />
def apply_laplacian(mat):<br />
<br />
    """This function applies a discretized Laplacian<br />
<br />
    in periodic boundary conditions to a matrix<br />
<br />
    For more information see<br />
<br />
    https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization<br />
<br />
    """<br />
<br />
<br />
<br />
    # the cell appears 4 times in the formula to compute<br />
<br />
    # the total difference<br />
<br />
    neigh_mat = -4*mat.copy()<br />
<br />
<br />
<br />
    # Each direct neighbor on the lattice is counted in<br />
<br />
    # the discrete difference formula<br />
<br />
    neighbors = [<br />
<br />
                    ( 1.0,  (-1, 0) ),<br />
<br />
                    ( 1.0,  ( 0,-1) ),<br />
<br />
                    ( 1.0,  ( 0, 1) ),<br />
<br />
                    ( 1.0,  ( 1, 0) ),<br />
<br />
                ]<br />
<br />
<br />
<br />
    # shift matrix according to demanded neighbors<br />
<br />
    # and add to this cell with corresponding weight<br />
<br />
    for weight, neigh in neighbors:<br />
<br />
        neigh_mat += weight * np.roll(mat, neigh, (0,1))<br />
<br />
<br />
<br />
    return neigh_mat<br />
<br />
<br />
<br />
# Define the update formula for chemicals A and B<br />
<br />
def update(A, B, DA, DB, f, k, delta_t):<br />
<br />
    """Apply the Gray-Scott update formula"""<br />
<br />
<br />
<br />
    # compute the diffusion part of the update<br />
<br />
    diff_A = DA * apply_laplacian(A)<br />
<br />
    diff_B = DB * apply_laplacian(B)<br />
<br />
<br />
<br />
    # Apply chemical reaction<br />
<br />
    reaction = A*B**2<br />
<br />
    diff_A -= reaction<br />
<br />
    diff_B += reaction<br />
<br />
<br />
<br />
    # Apply birth/death<br />
<br />
    diff_A += f * (1-A)<br />
<br />
    diff_B -= (k+f) * B<br />
<br />
<br />
<br />
    A += diff_A * delta_t<br />
<br />
    B += diff_B * delta_t<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def get_initial_A_and_B(N, random_influence = 0.2):<br />
<br />
    """get the initial chemical concentrations"""<br />
<br />
<br />
<br />
    # get initial homogeneous concentrations<br />
<br />
    A = (1-random_influence) * np.ones((N,N))<br />
<br />
    B = np.zeros((N,N))<br />
<br />
<br />
<br />
    # put some noise on there<br />
<br />
    A += random_influence * np.random.random((N,N))<br />
<br />
    B += random_influence * np.random.random((N,N))<br />
<br />
<br />
<br />
    # get center and radius for initial disturbance<br />
<br />
    N2, r = N//2, 50<br />
<br />
<br />
<br />
    # apply initial disturbance<br />
<br />
    A[N2-r:N2+r, N2-r:N2+r] = 0.50<br />
<br />
    B[N2-r:N2+r, N2-r:N2+r] = 0.25<br />
<br />
<br />
<br />
    return A, B<br />
<br />
<br />
<br />
def draw(A, B):<br />
<br />
    """return the matplotlib artists for animation"""<br />
<br />
    fig, ax = pl.subplots(1,2,figsize=(5.65,3))<br />
<br />
    imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')<br />
<br />
    imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')<br />
<br />
    ax[0].axis('off')<br />
<br />
    ax[1].axis('off')<br />
<br />
    ax[0].set_title('A')<br />
<br />
    ax[1].set_title('B')<br />
<br />
<br />
<br />
    return fig, imA, imB<br />
<br />
<br />
<br />
# =========== define model parameters ==========<br />
<br />
<br />
<br />
# update in time<br />
<br />
delta_t = 1.0<br />
<br />
<br />
<br />
# Diffusion coefficients<br />
<br />
DA = 0.16<br />
<br />
DB = 0.08<br />
<br />
<br />
<br />
# define birth/death rates<br />
<br />
f = 0.060<br />
<br />
k = 0.062<br />
<br />
<br />
<br />
# grid size<br />
<br />
N = 200<br />
<br />
<br />
<br />
# intialize the chemical concentrations<br />
<br />
A, B = get_initial_A_and_B(N)<br />
<br />
<br />
<br />
N_simulation_steps = 10000<br />
<br />
for step in range(N_simulation_steps):<br />
<br />
    A, B = update(A, B, DA, DB, f, k, delta_t)<br />
<br />
<br />
<br />
draw(A, B)<br />
<br />
<br />
<br />
# show the result<br />
<br />
pl.show()<br />
<br />

Pauline Raffestin
Administration
Pauline Raffestin est assistante administrative au sein de la Faculté Informatique et Communication de l’EPFL depuis 2016. Elle est gestionnaire du Laboratoire de Théorie du Calcul (THL4) du Prof. Michael Kapralov et du Laboratoire d’Informatique Réaliste (RGL) du Prof. Wenzel Jakob.

N’hésitez pas à la contacter pour toute question relative au Cours Turing. Elle se fera un plaisir de vous répondre.

Partenaires

Ce cours a reçu le généreux soutien de:

- la fondation Inspir
- la fondation Goehner


Contact

 Contact mail

Pour toutes demandes d'informations complémentaires ou autres remarques, vous pouvez vous adresser par mail à Pauline Raffestin.

EPFL IC Cours Turing
BC 246 (Bâtiment BC)
Station 14
CH-1015 Lausanne