Utilisation d'automate pour simuler une foule
Fermémamiemando Messages postés 33363 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 novembre 2024 - 5 déc. 2022 à 17:25
- Automate cellulaire python
- Citizen code python avis - Accueil - Outils
- Lcl dépôt chèque automate - Forum logiciel systeme
- 411 cellulaire quebec gratuit ✓ - Forum Mobile
- Recherche par numéro de téléphone cellulaire - Forum Mobile
3 réponses
Je ne suis pas expert en graphique, mais je pense intuitivement aux modules turtle ou pygame.
Le jeu de la vie comme modèle peut être intéressant, mais il n'est pas directionel et ne préserve pas les individus.
Modifié le 5 déc. 2022 à 15:47
Bonjour,
Je distinguerais deux étapes, la première étant optionnelle :
Étape 1 : voir l'état de ton graphe
Tu peux définir ta structure de graphe avec networkx (ou une librairie équivalente) et ensuite en faire le rendu graphique avec graphviz (plus précisément, le moteur neato) en lui passant en paramètre la chaîne dot que tu auras généré.
Voici par exemple à quoi ressemble la chaîne dot d'une grille de 2x2 sommets.
digraph G {
graph [fontcolor="black"; bgcolor="transparent"; rankdir="LR"]; node [color="black"; fontcolor="black"; fillcolor="transparent"]; edge [color="black"; fontcolor="black"];
node [shape="rectangle"; style="rounded, filled"];
vertex_0_0 [label=<(0,0)>; pos="0,0!"];
vertex_0_1 [label=<(0,1)>; pos="1,0!"];
vertex_1_0 [label=<(1,0)>; pos="0,-1!"];
vertex_1_1 [label=<(1,1)>; pos="1,-1!"];
vertex_0_0 -> vertex_1_0 [label=0.1];
vertex_0_0 -> vertex_0_1 [label=0.9];
vertex_0_1 -> vertex_0_0 [label=0.2];
vertex_0_1 -> vertex_1_1 [label=0.8];
vertex_1_0 -> vertex_0_0 [label=0.3];
vertex_1_0 -> vertex_1_1 [label=0.7];
vertex_1_1 -> vertex_0_1 [label=0.4];
vertex_1_1 -> vertex_1_0 [label=0.6];
}
L'avantage de graphviz c'est que tu peux même directement annoter les transitions avec les probabilité de tes arcs ou adapter des attributs (comme la couleur) en fonction de la probabilité.
Si le logiciel (pas le module python) est installé et fournit notamment la commande neato (paquet graphviz sous Linux, pas python3-graphviz), tu peux y faire appel en python avec la fonction dot_to_svg :
def error(*cls): print(*cls, file=sys.stderr) def run_graphviz(s_dot: str, layout_engine: str = "dot", format: str = "svg") -> bytes: """ Convert a dot string (graphviz format) into a graphic file. Args: s_dot: A string in the graphviz format. layout_engine: The graphviz engine used for the rendering. See "man dot" for more details. format: The output graphviz terminal. See "man dot" for more details. Returns: The bytes/str of the output image iff successful, None otherwise. """ cmd = ['dot', '-T' + format, '-K', layout_engine] dot = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) stdout_data, stderr_data = dot.communicate(s_dot.encode("utf-8")) status = dot.wait() if status == 0: if format == "svg": return stdout_data.decode("utf-8") else: return stdout_data else: error(f"dot returned {status}\n[==== stderr ====]\n{stderr_data.decode('utf-8')}") error("Input dot string was:\n%s\n" % s_dot) raise RuntimeError("run_graphviz: invalid string") def dot_to_svg(s_dot :str, layout_engine = "dot", format = "svg") -> str: bytes_img = run_graphviz(s_dot, layout_engine, format) if isinstance(bytes_img, bytes): # This should no more occur return bytes_img.decode("utf-8") elif isinstance(bytes_img, str): i = bytes_img.find("<svg") return bytes_img[i:] return None
Si tu travailles dans Jupyter, tu peux ensuite afficher le svg avec :
def html(s :str): """ Evaluate HTML code in a Jupyter Notebook. Args: s: A str containing HTML code. """ from IPython.display import display, HTML chart = HTML(s) # or chart = charts.plot(...) display(chart)
Bon je n'entre pas plus dans les détails car peut être que ton modèle probabiliste est suffisamment simple pour que tu n'aies pas besoin de donner ta chaîne de Markov.
Étape 2 : faire l'animation
Dans ce cas il existe plein de solutions techniques, comme le dit Pierrot, si tu te contentes de représenter chaque cellule par un carré coloré, cela se fait en turtle ou effectivement pygame. L'avantage de turtle c'est qu'il est installé de base avec python et il me paraît suffisant dans ton cas.
Voici un exemple de code que j'ai retapé à partir d'une discussion que j'ai vu passé il y a quelques semaines :
import numpy as np MAP = """1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 1 1 1 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 1 1 0 1 0 1 1 1 0 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 0 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1""" def load_matrix(s: str) -> np.array: return np.array([ [int(i) for i in line.split()] for line in s.splitlines() ]) load_matrix(MAP) import turtle import numpy as np from pprint import pprint import sys, traceback class Agent: def __init__(self, color: str, position: tuple, destination :tuple = None, planner = None): self.color = color self.position = position self.destination = destination self.planner = planner if self.planner: self.planner.update_position(position) self.planner.update_destination(destination) def update_position(self, position: tuple): self.position = position if self.planner: self.planner.update_position(position) def update_destination(self, destination: tuple): self.destination = destination if self.planner: self.planner.update_destination(destination) def query(self, ij_default: tuple = None) -> tuple: return self.planner.query() if self.planner else ij_default def is_done(self) -> bool: return self.position == self.destination class Maze: def __init__(self, matrix: np.array, agents: list): # Map self.xmin = -300 self.ymin = -300 self.xmax = 300 self.ymax = 300 canvas = turtle.getcanvas() screen = turtle.TurtleScreen(canvas) screen.setworldcoordinates(self.xmin, self.ymax, self.xmax, self.ymin) self.color_map = { i : color for (i, color) in enumerate( ["white", "grey", "yellow", "orange", "green"] ) } self.load_map(matrix) self.agents = agents self.map_destination_color = { agent.destination : agent.color for agent in agents } # Draw #turtle.exitonclick() self.draw_map() def compute_cell_step(self) -> int: (m, n) = self.matrix.shape w = (self.xmax - self.xmin) / n h = (self.ymax - self.ymin) / m return min(w, h) def load_map(self, matrix: np.array): self.matrix = matrix self.step = self.compute_cell_step() def to_xy(self, ij) -> tuple: (i, j) = ij return (self.xmin + j * self.step, (self.ymax - self.step) - i * self.step) @staticmethod def draw_square(xy: tuple, color: str, size: int, filled :bool =True): turtle.speed('fastest') turtle.setheading(0) turtle.tracer(0) turtle.up() turtle.goto(xy) turtle.down() turtle.pencolor(color) if filled: turtle.fillcolor(color) turtle.begin_fill() for _ in range(4): turtle.forward(size) turtle.left(90) if filled: turtle.end_fill() turtle.up() def cell_color(self, ij) -> str: return self.color_map.get(self.matrix[ij], "black") def draw_cell(self, ij: tuple): size = self.step xy = self.to_xy(ij) cell_color = self.cell_color(ij) Maze.draw_square(xy, cell_color, size, filled=True) for agent in self.agents: if agent.destination is not None and agent.destination == ij: Maze.draw_square(xy, agent.color, size, filled=False) def draw_cells(self): (m, n) = self.matrix.shape for i in range(m): for j in range(n): self.draw_cell((i, j)) def draw_destinations(self): size = self.step for (ij, color) in self.map_destination_color.items(): xy = self.to_xy(ij) Maze.draw_square(xy, color, size, filled=False) @staticmethod def draw_dot(xy: tuple, color: str, size: int): turtle.speed('fastest') turtle.setheading(0) turtle.tracer(0) turtle.up() turtle.goto(xy) turtle.forward(size / 2) turtle.left(90) turtle.forward(size / 2) turtle.down() turtle.dot(size, color) def draw_agent(self, agent: Agent): ij = agent.position color = agent.color size = 0.9 * self.step xy = self.to_xy(ij) Maze.draw_dot(xy, color, size) def draw_agents(self): for agent in self.agents: self.draw_agent(agent) def draw_map(self): self.draw_cells() self.draw_destinations() self.draw_agents() def move(self, agent: Agent, new_ij: tuple) -> tuple: ij = agent.position if ( not (0 <= new_ij[0] < self.matrix.shape[0]) or not (0 <= new_ij[1] < self.matrix.shape[1]) ): new_ij = ij elif self.matrix[new_ij] == 1: new_ij = ij else: xy = self.to_xy(ij) xy_new = self.to_xy(new_ij) if ij != new_ij: agent.update_position(new_ij) self.draw_cell(ij) self.draw_agent(agent) return new_ij def end(self, message = None): turtle.bye() if message is not None: print(message) def moves(self, dij_default: tuple = None) -> tuple: for agent in self.agents: ij_default = ( agent.position[0] + dij_default[0], agent.position[1] + dij_default[1] ) if dij_default else None new_ij = agent.query(ij_default) if new_ij is not None: self.move(agent, new_ij) if self.check_collision(agent): self.end("BOOOM") if self.check_victory(): self.end("BRAVO") def check_collision(self, agent) -> bool: ijs = [agent.position for agent in self.agents] if len(ijs) != len(set(ijs)): return True if any(self.matrix[ij] == 1 for ij in ijs): return True return False def check_victory(self) -> bool: return all(agent.is_done() for agent in self.agents) matrix = load_matrix(MAP) agents = [ Agent("red", (17, 11), (17, 10), None), Agent("blue", (3, 5), (26, 17), None), ] maze = Maze(matrix, agents) try: turtle.listen() # Listen for keyboard events turtle.onkeypress(lambda: maze.moves(( 0, -1)), "Left") turtle.onkeypress(lambda: maze.moves(( 0, 1)), "Right") turtle.onkeypress(lambda: maze.moves((-1, 0)), "Up") turtle.onkeypress(lambda: maze.moves(( 1, 0)), "Down") turtle.mainloop() except: turtle.bye() print(traceback.format_exc(), file=sys.stderr)
Ici le jeu dessine un labyrinthe et deux agent (rouge et bleu) dont le but est d'atteindre la case encadrée par leur couleur. À moins qu'un agent ait un planner, il se déplace (si possible) conformément à la flèche du clavier sur laquelle tu appuies. Ainsi appuyer sur la flèche droite déplace l'un des deux agents d'une case vers la droite (si possible), vérifie s'il est entré en collision avec un autre personnage, et ainsi de suite jusqu'à avoir déplacer tous les personnages.
Programmer une intelligence pour un agent consiste juste à implémenter son planner. Dans ton cas il serait basé sur les probabilité des transitions de ton graphe.
Bonne chance
5 déc. 2022 à 17:01
Bonjour,
Tu doit pouvoir trouver sur le net des simulations de mouvement brownien.
Il y en a même un d'intégré dans un vieux Python 27.
tu n'aura alors qu'à agir sur les paramètres de déplacement en créant un attracteur.
5 déc. 2022 à 17:13
Merci pour ta réponse, mais je ne pense pas que le mouvement brownien soit le bon modèle mathématiques, car un mouvement brownien est dans le plan (pas dans un espace discret comme un graphe) conditionné par des collisions (pas selon les probabilités assignées aux arcs du graphe).
5 déc. 2022 à 17:17
Une foule se déplace à priori dans un plan (en attendant les piétons volants).
5 déc. 2022 à 17:25
Je crois que tu as mal lu le modèle mathématique que jautomate veut utiliser. Je cite :
J'ai eu l'idée d'introduire un modèle probabiliste axé sur les automates cellulaires ( basé sur les probabilités de transition d'un piéton vers une cellule donnée, le sol étant discrétisé en grille de n cellules)
Comment appliquerais-tu le modèle du mouvement brownien dans ce contexte ?