Séance du 19/12/17

This commit is contained in:
Klafyvel 2017-12-19 17:54:13 +01:00
parent d64133d970
commit 60644cddd0
15 changed files with 1403 additions and 33 deletions

21
compte_rendu/Makefile Normal file
View file

@ -0,0 +1,21 @@
.PHONY:
.SUFFIXES:
COMP = mdbg
OUT = cours
TITLE = "Microéconomie"
PACKAGE = "{{MyPack2}}"
AUTHOR = "Hugo LEVY--FALK"
DOCUMENTCLASS = "article"
all:
$(COMP) $(OUT).mdbg --title $(TITLE) --packages $(PACKAGE) --date \\today --documentclass $(DOCUMENTCLASS) --author $(AUTHOR)
lualatex --shell-escape $(OUT).tex
lualatex --shell-escape $(OUT).tex
rm $(OUT).aux $(OUT).log $(OUT).out $(OUT).toc
rm $(OUT).tex
clean:
rm $(OUT).aux $(OUT).log $(OUT).out $(OUT).toc
rm $(OUT).tex

155
compte_rendu/MyPack2.sty Normal file
View file

@ -0,0 +1,155 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{MyPack2}
%%%%%%%% INCLUSIONS GÉNÉRALES %%%%%%%%%
\RequirePackage{babel}
%\RequirePackage{titlesec}
\RequirePackage{color}
\RequirePackage[a4paper]{geometry}
\RequirePackage[font=small,format=plain,labelfont=bf,up,
textfont=normal,up,
justification=justified,
singlelinecheck=false]{caption}
\RequirePackage[justification=centering]{caption}
\RequirePackage{xcolor} % Required for specifying custom colours
\definecolor{grey}{rgb}{0.9,0.9,0.9} % Colour of the box surrounding the title
\RequirePackage[utf8]{inputenc} % Required for inputting international characters
\RequirePackage[T1]{fontenc}
% \RequirePackage[sfdefault]{ClearSans} % Use the Clear Sans font (sans serif)
\RequirePackage{placeins}
\RequirePackage{listings}
\RequirePackage{graphicx}
\RequirePackage{amsfonts}
\definecolor{bleu}{RGB}{0,100,143}
\definecolor{gris}{RGB}{130,130,140}
\definecolor{grisBleu}{RGB}{65,115,141}
%%%%%%%% MATH %%%%%%%%%
\RequirePackage{stmaryrd}
\newcommand*\intervalleEntier[2]{\intervalle{\llbracket}{#1}{#2}{\rrbracket}}
\newcommand*\intervalle[4]{\left#1 #2 \, ; #3 \right#4}
\newcommand*\intervalleOO[2]{\intervalle{]}{#1}{#2}{[}}
\newcommand*\intervalleFF[2]{\intervalle{[}{#1}{#2}{]}}
\newcommand*\intervalleOF[2]{\intervalle{]}{#1}{#2}{]}}
\newcommand*\intervalleFO[2]{\intervalle{[}{#1}{#2}{[}}
\let\ensembleNombre\mathbb
\newcommand*\N{\ensembleNombre{N}}
\newcommand*\Z{\ensembleNombre{Z}}
\newcommand*\Q{\ensembleNombre{Q}}
\newcommand*\R{\ensembleNombre{R}}
\newcommand*\C{\ensembleNombre{C}}
\newcommand*\enstq[2]{\left\{#1,\; #2\right\}}
%\newcommand*\int[1]{\left\lfloor #1\right\rfloor}
%\newcommand*\norme[1]{\left\lVert#1\right\rVert}
%\newcommand*\abs[1]{\left\lvert#1\right\rvert}
\let\vecteur\overrightarrow
\newcommand*\Sys[1]{\left\{ \begin{aligned} #1 \end{aligned} \right. \kern-\nulldelimiterspace}
\newcommand*\application[5]{
#1 \colon
\begin{alignedat}{2} &#2 &\to &#3\\
&#4 &\mapsto &#5
\end{alignedat}
}
\newcommand*\applicationSigne[3]{
#1 \colon #2 \to #3
}
\newtheorem{defi}{Définition}[section]
\newtheorem{theo}{Théorème}[section]
\newtheorem{prop}{Proposition}[section]
\newtheorem{ex}{Exemple}[section]
%%%%%%%% SECTIONNEMENT %%%%%%%%%
%\renewcommand{\thesection}{\Roman{section}}
%\renewcommand{\thesubsection}{\arabic{subsection}}
\newcommand*\emptyPage{\newpage\null\thispagestyle{empty}\addtocounter{page}{-1}\newpage}
%%%%%%%% INTIALISATION DE LA PAGE %%%%%%%%%
\RequirePackage{fancyhdr}
\newcommand\initPage[3]{
\pagestyle{fancy}
\fancyhead{#1}
\lhead{#2}
\rhead{#3}
\rfoot{}
\lfoot{}
%\titleformat*{\section}{\Large\bfseries\color{bleu}\Roman{section}}
%\titleformat*{\subsection}{\large\bfseries\color{grisBleu}}
%\titleformat*{\subsubsection}{\bfseries\color{gris}}
%\titlespacing*{\section}{-3em}{*1}{*1}
%\titlespacing*{\subsection}{-2em}{*1}{*1}
%\titlespacing*{\subsubsection}{-1em}{*1}{*1}
}
%%%%%%%% TITRE %%%%%%%%M
\renewcommand{\maketitle}{
\begin{titlepage} % Suppresses displaying the page number on the title page and the subsequent page counts as page 1
%------------------------------------------------
% Grey title box
%------------------------------------------------
\topskip0pt
\vspace*{5cm}
\colorbox{grey}{
\parbox[t]{0.93\textwidth}{ % Outer full width box
\parbox[t]{0.91\textwidth}{ % Inner box for inner right text margin
\raggedleft % Right align the text
\fontsize{72pt}{80pt}\selectfont % Title font size, the first argument is the font size and the second is the line spacing, adjust depending on title length
\vspace{1cm} % Space between the start of the title and the top of the grey box
\@title
\vspace{1cm} % Space between the end of the title and the bottom of the grey box
}
}
}
\vfill % Space between the title box and author information
%------------------------------------------------
% Author name and information
%------------------------------------------------
\parbox[t]{0.93\textwidth}{ % Box to inset this section slightly
\raggedleft % Right align the text
\large % Increase the font size
{\Large \@author}\\[4pt] % Extra space after name
\hfill\rule{0.2\linewidth}{1pt}\\% Horizontal line, first argument width, second thickness
\@date
}
\end{titlepage}
\emptyPage
}
%%%%%%%% FIN DU DOCUMENT %%%%%%%%%
\newcommand{\roadMap}{
\clearpage
\listoffigures
\clearpage
\listoftables
}
% Fin du package
\endinput

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -1,33 +0,0 @@
class Graph:
"""Implémente un graphe non orienté."""
def __init__(self, nom):
"""Initialise un graphe vide.
:param nom: Nom du graphe
"""
self.nom = nom
class Sommet:
"""Implémente un sommet de graphe."""
def __init__(self, pos):
"""Initialise un sommet.
:param pos: couple donnant la position du point.
"""
self.pos = pos
class Arete:
"""Implémente une arête de graphe."""
def __init__(self, longueur, v_moyenne):
"""Initialise une arête.
:param longueur: longueur de l'arête.
:param v_moyenne: vitesse moyenne sur l'arête.
"""
self.longueur = longueur
self.v_moyenne = v_moyenne

316
graphe.py Normal file
View file

@ -0,0 +1,316 @@
import random
import triangulation
class Graphe:
"""Implémente un graphe non orienté."""
def __init__(self, nom):
"""Initialise un graphe vide.
:param nom: Nom du graphe
"""
self.nom = nom
self.sommets = []
self.aretes = []
def renomme(self, nom):
"""Renome le graphe
:param nom: Nouveau nom du graphe.
"""
self.nom = nom
def ajouteSommet(self, x, y):
"""Ajoute le sommet s au graphe.
:param x: abcisse du sommet.
:param y: ordonnée du sommet.
:return: Le sommet créé.
"""
s = Sommet((x, y), len(self.sommets))
self.sommets.append(s)
return s
def connecte(self, s1, s2, longueur, v_moyenne):
"""Connecte les sommets s1 et s2.
:param s1: premier sommet.
:param s2: deuxième sommet.
:param longueur: longueur de l'arrête.
:param v_moyenne: vitesse moyenne sur l'arrête.
:return: L'arête créée.
"""
a = Arete(s1, s2, longueur, v_moyenne)
self.aretes.append(a)
return a
def n(self):
"""Retourne le nombre de sommets du graphe."""
return len(self.sommets)
def m(self):
"""Retourne le nombre d'arrêtes du graphe."""
return len(self.aretes)
def __str__(self):
return "V({nom})=[\n{noeuds}\n]\nE({nom})=[\n{aretes}\n]\n".format(
nom=self.nom,
aretes='\n'.join([str(v) for v in self.aretes]),
noeuds='\n'.join([str(n) for n in self.sommets])
)
def trace(self, dest):
"""Affiche le graphe sur la destination.
:param dest: instance de Afficheur.
"""
for s in self.sommets:
dest.changeCouleur(s.couleur)
dest.tracePoint((s.x(), s.y()))
dest.traceTexte((s.x(), s.y()), 'v'+str(s.num))
for a in self.aretes:
dest.changeCouleur(a.couleur)
dest.traceLigne((a.s1.x(), a.s1.y()), (a.s2.x(), a.s2.y()))
def ajouteRoute(self, v1, v2, vmax):
"""Ajoute une route de distance euclidienne entre v1 et v2.
:param v1: Premier sommet.
:param v2: Deuxième sommet.
:param vmax: vitesse maximale sur la route.
:return: Route créée.
"""
return self.connecte(v1, v2, v1.distance(v2), vmax)
def ajouteNationale(self, v1, v2):
"""Ajoute une nationale au graphe. (rouge et vmax = 90km/h).
:param v1: Premier sommet.
:param v2: Deuxième sommet.
:return: route créée.
"""
a = self.ajouteRoute(v1, v2, 90)
a.couleur = (1., 0., 0.)
return a
def ajouteDepartementale(self, v1, v2):
"""Ajoute une départementale au graphe. (jaune et vmax = 60km/h).
:param v1: Premier sommet.
:param v2: Deuxième sommet.
:return: route créée.
"""
a = self.ajouteRoute(v1, v2, 60)
a.couleur = (1., 1., 0.)
return a
class Sommet:
"""Implémente un sommet de graphe."""
def __init__(self, pos, num, couleur=(0., 0., 0.)):
"""Initialise un sommet.
:param pos: couple donnant la position du point.
:param num: numéro du sommet.
:param couleur: couleur du sommet.
"""
self.pos = pos
self.num = num
self.couleur = couleur
def __str__(self):
return "v{} (x = {} km y = {} km)".format(
str(self.num),
str(self.x()),
str(self.y())
)
def distance(self, v):
"""Calcule la distance entre deux points.
:param v: Point de calcul de la distance.
"""
return ((self.x()-v.x())**2 + (self.y()-v.y())**2)**(1/2)
def x(self):
"""Retourne l'abcisse de x."""
return self.pos[0]
def y(self):
"""Retourne l'ordonnée de y."""
return self.pos[1]
class Arete:
"""Implémente une arête de graphe."""
def __init__(self, s1, s2, longueur, v_moyenne, couleur=(0., 0., 0.)):
"""Initialise une arête.
:param s1: sommet 1.
:param s2: sommet 2.
:param longueur: longueur de l'arête.
:param v_moyenne: vitesse moyenne sur l'arête.
:param couleur: couleur de l'arête.
"""
self.s1 = s1
self.s2 = s2
self.longueur = longueur
self.v_moyenne = v_moyenne
self.couleur = couleur
def voisin(self, s):
"""Retourne le sommet voisin de s dans l'arête.
:param s: Un sommet de l'arête.
"""
if s == self.s1:
return self.s2
else:
return self.s1
def __str__(self):
return " v{v1}, v{v2} (long. = {lon} km vlim. = {v} km/h)".format(
v1=str(self.s1.num),
v2=str(self.s2.num),
lon=str(self.longueur),
v=str(self.v_moyenne)
)
def pointsAleatoires(n, L):
"""Crée un graphe de n points aléatoires non reliés dans le carré centré en
0 de largeure L.
:param n: nombre de points.
:param L: Côté du carré.
"""
g = Graphe("Graphe aléatoire")
for _ in range(n):
x, y = random.uniform(-L/2, L/2), random.uniform(-L/2, L/2)
g.ajouteSommet(x, y)
return g
def test_gabriel(g, v1, v2):
"""Teste si on peut connecter deux sommets selon le critère de Gabriel.
:param g: Le graphe.
:param v1: Premier sommet.
:param v2: Deuxième sommet.
"""
milieu = Sommet(((v1.x()+v2.x())/2, (v1.y()+v2.y())/2), -1)
rayon = v1.distance(v2)/2
ajoute = True
for v3 in g.sommets:
if v3 in [v1, v2]:
continue
elif v3.distance(milieu) < rayon:
ajoute = False
break
return ajoute
def gabriel(g, ignore_gvr=False):
"""Crée le graphe de Gabriel associé à g avec des routes démartementales.
:param g: Un graphe sans arrêtes.
:param ignore_gvr: booléen indiquant si on ne doit pas ajouter une arrête
quand gvr en ajoute une.
"""
for v1 in g.sommets:
for v2 in g.sommets:
if v2 == v1:
continue
if test_gabriel(g, v1, v2):
if (ignore_gvr and not test_gvr(g, v1, v2)) or not ignore_gvr:
g.ajouteDepartementale(v1, v2)
def test_gvr(g, v1, v2):
"""Teste si on peut connecter deux sommets selon le critère GVR.
:param g: Le graphe.
:param v1: Premier sommet.
:param v2: Deuxième sommet.
"""
rayon = v1.distance(v2)
ajoute = True
for v3 in g.sommets:
if v3 in [v1, v2]:
continue
elif v3.distance(v1) < rayon and v3.distance(v2) < rayon:
ajoute = False
break
return ajoute
def gvr(g):
"""Crée le graphe GVR associé à g avec des routes nationales.
:param g: Un graphe sans arrêtes.
"""
for v1 in g.sommets:
for v2 in g.sommets:
if v2 == v1:
continue
if test_gvr(g, v1, v2):
g.ajouteNationale(v1, v2)
def reseau(g):
"""Construit une carte routière avec comme nationales les routes obtenues
par la méthode GVR et départementales celles de Gabriel.
:param g: Un raphe sans arêtes.
"""
gabriel(g, ignore_gvr=True)
gvr(g)
def delaunay(g):
"""Crée une triangulation de Delaunay à partir d ' un nuage de point"""
t = triangulation.Triangulation(g)
# Définit une fonction destinée à être appelée
# pour toute paire (s1,s2) de sommets
# qui forme une arête dans la triangulation de Delaunay.
# v3 et v4 sont les troisièmes sommets des deux triangles
# ayant (s1,s2) comme côté.
def selectionneAretes(graphe, v1, v2, v3, v4):
# Fait de chaque arête de la triangulation
# une nationale
graphe.ajouteNationale(v1, v2)
# Construit le graphe de retour, égal à la triangulation de Delaunay
g = t.construitGrapheDeSortie(selectionneAretes)
g.renomme("Delaunay(" + str(g.n()) + ")")
return g
def reseauRapide(g):
"""Crée une triangulation de Delaunay à partir d ' un nuage de point"""
t = triangulation.Triangulation(g)
# Définit une fonction destinée à être appelée
# pour toute paire (s1,s2) de sommets
# qui forme une arête dans la triangulation de Delaunay.
# v3 et v4 sont les troisièmes sommets des deux triangles
# ayant (s1,s2) comme côté.
def selectionneAretes(graphe, v1, v2, v3, v4):
if test_gabriel(graphe, v1, v2):
if test_gvr(graphe, v1, v2):
graphe.ajouteNationale(v1, v2)
else:
graphe.ajouteDepartementale(v1, v2)
# Construit le graphe de retour, égal à la triangulation de Delaunay
g = t.construitGrapheDeSortie(selectionneAretes)
g.renomme("Delaunay(" + str(g.n()) + ")")
return g

195
graphique.py Normal file
View file

@ -0,0 +1,195 @@
# coding: utf-8
import sys
import numpy as np
import math
import copy
import PySide.QtCore as qtcore
import PySide.QtGui as qtgui
import traceback
class Afficheur(qtgui.QWidget):
afficheurs = []
size = (800, 600)
coord = np.array((50, 50))
decalage = np.array((40,40))
def __init__(self, sujet, centre, ech):
super(Afficheur, self).__init__()
if(not "trace" in dir(sujet)):
raise Exception('Méthode "trace" non définie dans la classe ' + str(sujet.__class__))
app = qtgui.QApplication.instance()
if not app:
app = qtgui.QApplication(sys.argv)
desktop = app.desktop()
screen = desktop.screenGeometry(desktop.screenNumber(self))
self.rayon = 4
self.ech = ech
self.centre = np.array(centre)
self.crayon = None
self.sujet = sujet
self.setStyleSheet("background-color: gray")
self.center = np.array(Afficheur.size) / 2.
self.setGeometry(Afficheur.coord[0] + screen.x(), Afficheur.coord[1] + screen.y(), Afficheur.size[0], Afficheur.size[1])
Afficheur.coord += Afficheur.decalage
self.setWindowTitle("Afficheur")
self.show()
def __pointVersPixel(self, p):
p = np.array(p)
pixel = (p - self.centre) * self.ech
pixel[1] = -pixel[1]
pixel += self.center
return qtcore.QPoint(pixel[0],pixel[1])
def __pixelVersPoint(self, pixel):
p = np.array((pixel.x(), pixel.y())) - self.center
p[1] = -p[1]
p = p / self.ech + self.centre
return p
def __pixelVersVecteur(self, pixel1, pixel2):
assert isinstance(pixel1, qtcore.QPoint)
assert isinstance(pixel2, qtcore.QPoint)
v = np.array((pixel2.x(), pixel2.y())) - np.array((pixel1.x(), pixel1.y()))
v[1] = -v[1]
v = v / self.ech
return v
def tracePoint(self, p):
assert self.crayon != None
assert isinstance(p, tuple) or isinstance(p, np.ndarray)
assert isinstance(p[0], float)
assert isinstance(p[1], float)
pixel = self.__pointVersPixel(p)
self.crayon.drawEllipse(pixel, self.rayon, self.rayon)
def traceLigne(self, p1, p2):
assert self.crayon != None
assert isinstance(p1, tuple) or isinstance(p1, np.ndarray)
assert isinstance(p1[0], float)
assert isinstance(p1[1], float)
assert isinstance(p2, tuple) or isinstance(p2, np.ndarray)
assert isinstance(p2[0], float)
assert isinstance(p2[1], float)
pixel1 = self.__pointVersPixel(p1)
pixel2 = self.__pointVersPixel(p2)
self.crayon.drawLine(pixel1, pixel2)
def changeCouleur(self, couleur):
assert self.crayon != None
assert isinstance(couleur, tuple)
assert isinstance(couleur[0], float)
assert isinstance(couleur[1], float)
assert isinstance(couleur[2], float)
c = qtgui.QColor(couleur[0]*255, couleur[1]*255, couleur[2]*255)
self.crayon.setPen(c)
self.crayon.setBrush(c)
def traceTexte(self, p, texte):
assert isinstance(p, tuple) or isinstance(p, np.ndarray)
assert isinstance(p[0], float)
assert isinstance(p[1], float)
assert isinstance(texte, str)
pixel = self.__pointVersPixel(p)
pixel += qtcore.QPoint(10,-10)
self.crayon.drawText(pixel, texte)
def renomme(self, titre):
# assert isinstance(titre, str)
# titre = unicode(titre, 'utf-8')
self.setWindowTitle(titre)
def mousePressEvent(self, QMouseEvent):
pos = QMouseEvent.pos()
self.clic = pos
pos = self.__pixelVersPoint(pos)
self.centre = self.centre
def mouseMoveEvent(self, QMouseEvent):
pos = QMouseEvent.pos()
self.centre -= self.__pixelVersVecteur(self.clic, pos)
self.clic = pos
self.update()
def mouseReleaseEvent(self, QMouseEvent):
pos = QMouseEvent.pos()
self.centre -= self.__pixelVersVecteur(self.clic, pos)
self.clic = pos
self.update()
def wheelEvent(self, event):
pos = event.pos()
C = self.__pixelVersPoint(pos)
k1 = self.ech
k2 = k1 * math.exp(0.001 * event.delta())
self.centre = (self.centre * k1 + C * (k2 -k1)) / k2
self.ech = k2
self.update()
def paintEvent(self, event):
if(self.crayon != None):
return
self.crayon = qtgui.QPainter(self)
self.trace()
self.crayon = None
def trace(self):
self.crayon.setFont(qtgui.QFont('Decorative', 10))
if(self.sujet != None):
try:
self.sujet.trace(self)
except AttributeError:
self.close()
qtgui.QApplication.quit()
raise Exception('Méthode "trace" non définie dans la classe ' + str(self.sujet.__class__))
except BaseException:
traceback.print_exc()
self.close()
qtgui.QApplication.quit()
L = 100.;
x = 20; y = 20;
self.crayon.setPen('white')
msg = '{0:.2f} km'.format(L / self.ech)
l = self.crayon.fontMetrics().boundingRect(msg).width()
self.crayon.drawText(x + (L-l)/2, y-2, msg);
self.crayon.drawLine(x, y, x + L, y);
self.crayon.drawLine(x, y - L/20, x, y + L/10);
self.crayon.drawLine(x + L, y - L/20, x + L, y + L/10);
def sauvegarde(self):
filename = qtgui.QFileDialog.getSaveFileName(self, 'Fichier PDF')
if filename:
printer = qtgui.QPrinter(qtgui.QPrinter.HighResolution)
printer.setPageSize(qtgui.QPrinter.A4)
printer.setColorMode(qtgui.QPrinter.Color)
printer.setOutputFormat(qtgui.QPrinter.PdfFormat)
printer.setOutputFileName(filename)
self.crayon = qtgui.QPainter(printer)
self.trace()
self.crayon = None
def affiche(sujet, centre, ech, blocage = True):
'''Affiche dans une fenêtre l'objet sujet qui doit avoir une méthode trace'''
assert isinstance(centre, tuple)
assert isinstance(ech, float)
sujet = copy.deepcopy(sujet)
app = qtgui.QApplication.instance()
if not app:
app = qtgui.QApplication(sys.argv)
a = Afficheur(sujet, centre, ech)
Afficheur.afficheurs.append(a)
if(blocage):
bloque()
return a
def bloque():
app = qtgui.QApplication.instance()
if not app:
app = qtgui.QApplication(sys.argv)
app.exec_()

109
polygone.py Normal file
View file

@ -0,0 +1,109 @@
# coding: utf-8
# La ligne précédente est indispensable pour accpeter les accents dans le fichier
# Importe les modules qui seront nécessaires
import math # Fonctions mathématiques : math.cos, math.sin, math.pi, etc
import random # Générateurs de nombres aléatoires
import numpy # Calcul numérique sur des vecteurs, matrices, etc
# Importe le fichier graphique.py qui
import graphique
class Sommet:
'''Classe représentant un sommet d'un polygone'''
def __init__(self, theta, r):
'''Constructeur de la classe Sommet : (theta,r) sont les coordonnées polaires du sommet self'''
self.deplace(theta, r)
def deplace(self, theta, r):
'''Déplace le sommet self: (theta,r) sont les nouvelles coordonnées polaires'''
# Sauvegarde les coordonnées polaires dans des attributs de l'objet self
self.theta = theta
self.r = r
# Calcule les coordonnées cartésiennes (pour l'affichage)
# On utilise la bibliothèque de calcul numérique numpy.
self.pos = numpy.array([math.cos(theta), math.sin(theta)]) * r
def __str__(self):
'''Fonction spéciale de conversion en chaîne de caractères'''
chaine = '({:0.2f},{:0.2f})'.format(self.pos[0], self.pos[1])
return chaine
class Polygone:
''' Classe représentant un polygone du plan'''
def __init__(self, n, R):
'''Constructeur d'un objet Polygone : crée un polygone régulier
à n sommets placés sur le cercle de rayon R centré sur l'origine'''
# Vérifie que les arguments ont le type attendu
assert isinstance(n, int)
assert isinstance(R, float)
# Crée comme attribut de self une liste pour accueillir les sommets
self.sommets = []
# Crée un attribut pour stocker le nom du polygone
self.nom = str(n) + "-polygone régulier"
# Remplie la liste des n sommets
alpha = 2. * math.pi / n
angle = math.pi / 2.
for _ in range(n):
self.sommets.append(Sommet(angle, R))
angle += alpha
def __str__(self):
'''Fonction spéciale de conversion en chaîne de caractères'''
chaine = self.nom + ' = ('
if(len(self.sommets) > 0):
chaine += str(self.sommets[0])
for s in self.sommets[1:]:
chaine += ', ' + str(s)
chaine += ')'
return chaine
def secoue(self, amplitudeAngulaire, amplitudeRadiale):
'''Fonction qui déplace aléatoirement chaque sommet selon une amplitude angulaire et radiale réglable'''
# Modifie les coordonnées de chaque sommet à l'aide de la méthode deplace
for s in self.sommets:
s.deplace(
s.theta + (random.random() * 2. - 1.) * amplitudeAngulaire,
s.r * (1. + (random.random() * 2. - 1.) * amplitudeRadiale)
)
# Change le nom du polygone
self.nom = str(len(self.sommets)) + "-polygone secoué"
def trace(self, afficheur):
'''Fonction de dessin'''
assert isinstance(afficheur, graphique.Afficheur)
afficheur.renomme(self.nom)
precedent = self.sommets[-1]
afficheur.changeCouleur((0.,0.,0.))
for suivant in self.sommets:
afficheur.traceLigne(precedent.pos, suivant.pos)
precedent = suivant
afficheur.changeCouleur((1.,0.,0.))
for sommet in self.sommets:
afficheur.tracePoint(sommet.pos)
if __name__ == "__main__":
triangle = Polygone(3, 10.)
print(triangle)
graphique.affiche(triangle, (0., 0.), 10., blocage = False)
heptagone = Polygone(7, 10.)
heptagone.secoue(math.pi / 5, 0.1)
graphique.affiche(heptagone, (0., 0.), 10.)

136
tas.py Normal file
View file

@ -0,0 +1,136 @@
# coding: utf-8
class Tas:
class Element:
def __init__(self, valeur, priorite, index):
self.valeur = valeur
self.priorite = priorite
self.index = index
def __str__(self):
return str(self.valeur)
def __init__(self, fonctionPriorite):
self.L = []
self.fonctionPriorite = fonctionPriorite
def __str__(self):
s = "["
for elt in self.L:
s += " " + str(elt)
s += "]"
return s
def __parent(self, elt):
if(elt.index == 0):
return None
else:
return self.L[(elt.index-1) // 2]
def __fils_gauche(self, elt):
i = 2 * elt.index + 1
if(i < len(self.L)):
return self.L[i]
else:
return None
def __fils_droit(self, elt):
i = 2 * elt.index + 2
if(i < len(self.L)):
return self.L[i]
else:
return None
def __deplace(self, elt, index):
assert isinstance(elt, Tas.Element)
ancien = elt.index
self.L[index] = elt
elt.index = index
return ancien
def __promeut(self, elt):
while(True):
parent = self.__parent(elt)
if(parent == None):
break
if(parent.priorite >= elt.priorite):
break
elt.index = self.__deplace(parent, elt.index)
self.__deplace(elt, elt.index)
def actualise(self, elt):
assert isinstance(elt, Tas.Element)
elt.priorite = self.fonctionPriorite(elt.valeur)
self.__promeut(elt)
def ajoute(self, valeur):
elt = Tas.Element(valeur, self.fonctionPriorite(valeur), len(self.L))
self.L.append(elt)
self.__promeut(elt)
return elt
def empty(self):
return len(self.L) == 0
def pop(self):
n = len(self.L)
if(n == 0):
return None
tete = self.L[0]
elt = self.L[n - 1]
elt.index = 0
while True:
filsGauche = self.__fils_gauche(elt)
filsDroit = self.__fils_droit(elt)
plusPrioritaire = elt
if(filsGauche != None and filsGauche.priorite > plusPrioritaire.priorite):
plusPrioritaire = filsGauche
if(filsDroit != None and filsDroit.priorite > plusPrioritaire.priorite):
plusPrioritaire = filsDroit
elt.index = self.__deplace(plusPrioritaire, elt.index)
if(plusPrioritaire is elt):
break
self.L.pop()
return tete.valeur
#########################################
# Exemple d'utilisatio de la classe Tas #
# Tri de tâches par ordre chronologique #
#########################################
class Tache:
'''Tache devant être effectuée avant une date limite'''
def __init__(self, jour, nom):
self.jour = jour
self.nom = nom
# Cet attribut servira à accueillir la clé du tas
self.cle = None
def __str__(self):
return self.nom + " ({})".format(self.jour)
if __name__ == "__main__":
# Le niveau de priorité d'un événement x est -x.jour : on trie donc les événements par ordre chronologique
def calculePriorite(tache):
return -tache.jour
# On crée un tas dont les éléments sont des événements triés par ordre chronologique
T = Tas(calculePriorite)
# Ajoute des événements au tas
evts = [ Tache(5, "T1"), Tache(10, "T2"), Tache(5, "T3"), Tache(3, "T4")]
for evt in evts:
evt.cle = T.ajoute(evt)
# Supposons que la tache 2 devienne soudain assez urgente
evts[1].jour = 4
T.actualise(evts[1].cle)
# Retirons dans l'ordre chronologie les éléments du tas
while(not T.empty()):
print(T.pop())

172
test.py Normal file
View file

@ -0,0 +1,172 @@
import graphe
import graphique
import copy
import numpy as np
import matplotlib.pyplot as pl
import time
def creerGrapheFigure1():
""" Crée le graphe de la figure 1 """
g = graphe.Graphe("Graphe de la figure 1")
s1 = g.ajouteSommet(1.0, 1.0)
s2 = g.ajouteSommet(2.0, 3.5)
s3 = g.ajouteSommet(2.5, 2.5)
s4 = g.ajouteSommet(5.0, 2.0)
s1.couleur = (1., 1., 0.)
s2.couleur = (0., 0., 1.)
s3.couleur = (1., 0., 0.)
s4.couleur = (1., 1., 0.)
a = g.connecte(s1, s2, 4.0, 90.)
a.couleur = (1., 1., 0.)
g.connecte(s1, s4, 5.2, 124.)
g.connecte(s2, s3, 2.0, 54.)
g.connecte(s2, s4, 5.0, 90.)
return g
def testQuestion1_2():
"""' Teste que la création d ' un graphe ne plante pas
print Question 1.2 :"""
creerGrapheFigure1()
print("Ok. Pas de plantage")
def testQuestion1_3():
""" Teste l ' affichage d ' un graphe dans la console"""
print("Question 1.3 :")
g = creerGrapheFigure1()
print(g)
def testQuestion1_4():
""" Teste du dessin d'un graphe."""
print("Question 1.4:")
graphique.affiche(creerGrapheFigure1(), (3., 2.), 100.)
def testQuestion2_2():
"""Teste de génération aléatoire de graphe."""
print("Question 2.2:")
graphique.affiche(graphe.pointsAleatoires(5, 30), (0, 0), 10.)
def testQuestion2_4():
"""Teste de gabriel et gvr."""
print("Question 2.4")
g = graphe.pointsAleatoires(30, 30)
g.renomme("Gabriel")
g1 = copy.deepcopy(g)
g1.renomme("GVR")
graphe.gabriel(g)
graphe.gvr(g1)
graphique.affiche(g, (0, 0), 10.)
graphique.affiche(g1, (0, 0), 10.)
def testQuestion2_5():
"""Teste de la création de réseau."""
g = graphe.pointsAleatoires(30, 30)
graphe.reseau(g)
graphique.affiche(g, (0, 0), 10.)
def chronometre(fonctionTest, fonctionPreparation, parametres):
''' Mesure le temps d ' exécution fonctionTest pour différentes valeurs d '
un paramètres '''
temps = []
# Pour chaque valeur de paramètre
for p in parametres:
# Génère les entrées du test pour la valeur p
entrees = fonctionPreparation(p)
# Lance le test pour ces entrées
print("t({}) = ".format(p), end="", flush=True)
debut = time.time()
fonctionTest(entrees)
fin = time.time()
# Mesure le temps d ' exécution
t = (fin - debut)
print("{:.2f} s".format(t))
temps.append(t)
return temps
def testQuestion2_6():
"""Mesure la performance de graphe.reseau"""
prepare = lambda p : graphe.pointsAleatoires(p, 10)
valeurs_n = np.arange(1, 200)
temps = chronometre(graphe.reseau, prepare, valeurs_n)
pl.close('all')
pl.title("Mesure du temps d'exécution de `reseau`.")
pl.plot(valeurs_n, temps)
pl.xlabel("n")
pl.ylabel("temps")
pl.show()
pl.title("Mesure du temps d'exécution de `reseau`.")
pl.loglog(valeurs_n, temps, label='temps de calcul')
pl.loglog(valeurs_n, (lambda x : x**3)(valeurs_n), label='$x\mapsto x^3$')
pl.legend(loc='best')
pl.xlabel("n")
pl.ylabel("temps")
pl.show()
def testQuestion2_7():
"""Compare la création de graphe de gabriel et ed delaunay."""
prepare = lambda p : graphe.pointsAleatoires(p, 10)
valeurs_n = np.arange(1, 200)
temps1 = chronometre(graphe.gabriel, prepare, valeurs_n)
temps2 = chronometre(graphe.delaunay, prepare, valeurs_n)
pl.close('all')
pl.title("Comparaison du temps pour `delaunay` et `gabriel`")
pl.plot(valeurs_n, temps1, label='gabriel')
pl.plot(valeurs_n, temps2, label='delaunay')
pl.legend(loc='best')
pl.xlabel('n')
pl.ylabel('temps')
pl.show()
def testQuestion2_8():
"""Compare le reseau naif et non naif."""
g = graphe.pointsAleatoires(30, 30)
g1 = copy.deepcopy(g)
g.renomme("Naïf")
g1.renomme("Non naïf")
graphe.reseau(g)
graphe.reseauRapide(g1)
graphique.affiche(g, (0, 0), 10.)
graphique.affiche(g1, (0, 0), 10.)
def testQuestion2_9():
"""Compare le temps de création des deux méthodes de création de réseau"""
prepare = lambda p : graphe.pointsAleatoires(p, 10)
valeurs_n = list(map(lambda x: int(x), np.logspace(1, 3, 30)))
temps1 = chronometre(graphe.reseau, prepare, valeurs_n)
temps2 = chronometre(graphe.reseauRapide, prepare, valeurs_n)
pl.close('all')
pl.title("Comparaison du temps d'exécution de `reseau` et `reseauRapide`.")
pl.plot(valeurs_n, temps1, label='reseau')
pl.plot(valeurs_n, temps2, label='reseauRapide')
pl.legend(loc='best')
pl.xlabel("n")
pl.ylabel("temps")
pl.show()
pl.title("Comparaison du temps d'exécution de `reseau` et `reseauRapide`.")
pl.loglog(valeurs_n, temps1, label='reseau')
pl.loglog(valeurs_n, temps2, label='reseauRapide')
pl.legend(loc='best')
pl.xlabel("n")
pl.ylabel("temps")
pl.show()
# testQuestion1_2()
# testQuestion1_3()
# testQuestion1_4()
# testQuestion2_2()
# testQuestion2_4()
# testQuestion2_5()
# testQuestion2_6()
# testQuestion2_7()
# testQuestion2_8()
testQuestion2_9()

299
triangulation.py Normal file
View file

@ -0,0 +1,299 @@
# coding: utf-8
import sys
import math
def distanceAuCarre(v1, v2):
dx = (v1.x() - v2.x())
dy = (v1.y() - v2.y())
return dx**2 + dy**2
def conditionDeDelaunay(A, B, C, D):
dab2 = distanceAuCarre(A, B)
dad2 = distanceAuCarre(A, D)
dbc2 = distanceAuCarre(B, C)
dbd2 = distanceAuCarre(B, D)
dcd2 = distanceAuCarre(C, D)
cosa = (dab2 + dad2 - dbd2) / (2 * math.sqrt(dab2) * math.sqrt(dad2))
cosc = (dbc2 + dcd2 - dbd2) / (2 * math.sqrt(dbc2) * math.sqrt(dcd2))
sina2 = 1. - cosa * cosa
if(sina2 > 0.):
sina = math.sqrt(sina2)
else:
sina = 0.
sinc2 = 1. - cosc * cosc
if(sinc2 > 0.):
sinc = math.sqrt(sinc2)
else:
sinc = 0.
return sina * cosc + cosa * sinc >= 0
class Triangulation:
class QuadEdge:
'''Classe définissant un quad-edge : une arête connectée à deux faces et deux sommets'''
def __init__(self, f1, f2, v1, v2):
self.f1 = f1
self.f2 = f2
self.v1 = v1
self.v2 = v2
def __eq__(self, e):
'''Méthode qui teste si deux quad-edges ont même extrémités'''
if((self.v1 == e.v1) and (self.v2 == e.v2)):
return True
elif((self.v1 == e.v2) and (self.v2 == e.v1)):
return True
else:
return False
def __str__(self):
return str(self.v1) + " - " + str(self.v2)
def remplaceFace(self, ancienneFace, nouvelleFace):
'''Méthode qui remplace une face adjacente au quad-edge par une autre'''
if(self.f1 == ancienneFace):
self.f1 = nouvelleFace
else:
self.f2 = nouvelleFace
def lanceAlgorithme(self):
# Construit la triangulation initiale. Complexité en O(n log(n))
self.construitTriangulationInitiale()
# Bascule les arêtes de la triangulation jusqu'à obtenir la triangulation de Delaunay
self.basculeAretes()
# Efface les sommets à l'infini
for _ in range(3):
self.graphe.sommets.pop()
def __init__(self, g):
'''Constructeur de la classe triangulation qui prend en entrée un nuage de points
et crée une triangulation de Delaunay'''
self.racine = None
self.quadEdges = []
self.graphe = g
self.lanceAlgorithme()
class Triangle:
def __init__(self, v1, v2, v3):
self.v1 = v1
self.v2 = v2
self.v3 = v3
self.t12 = None
self.t13 = None
self.t23 = None
self.e12 = None
self.e13 = None
self.e23 = None
def contient(self, v):
''' Méthode qui teste si un sommet est à l'intérieur d'un triangle'''
v1 = self.v1
v2 = self.v2
v3 = self.v3
det = (v1.x() - v3.x()) * (v2.y() - v3.y()) - \
(v1.y() - v3.y()) * (v2.x() - v3.x())
c1 = ((v2.y() - v3.y()) * (v.x() - v3.x()) +
(v3.x() - v2.x()) * (v.y() - v3.y())) * det
c2 = ((v3.y() - v1.y()) * (v.x() - v3.x()) +
(v1.x() - v3.x()) * (v.y() - v3.y())) * det
return (c1 > 0) and (c2 > 0) and (c1 + c2 < det * det)
def trouve(self, v):
'''Méthode récursive qui renvoie le triangle d'une triangulation qui contient un sommet.
Renvoie le triangle contenant v, None si v n'est pas dans la triangulation'''
t12 = self.t12
t13 = self.t13
t23 = self.t23
if(t12 == None):
return self
else:
if(t12.contient(v)):
return t12.trouve(v)
elif(t13.contient(v)):
return t13.trouve(v)
elif(t23.contient(v)):
return t23.trouve(v)
else:
return None
def aPourSommet(self, v):
'''Méthode qui teste si un sommet est un sommet d'un triangle
Renvoie vrai si v est un sommet du triangle'''
return self.v1 == v or self.v2 == v or self.v3 == v
def troisiemeSommet(self, a, b):
''' Renvoie le troisième sommet d'un triangle à partir des deux autres'''
if(self.v1 != a and self.v1 != b):
return self.v1
elif(self.v2 != a and self.v2 != b):
return self.v2
else:
return self.v3
def remplaceSommet(self, ancienSommet, nouveauSommet):
''' Méthode qui substitue un sommet par un autre dans un triangle '''
if(self.v1 == ancienSommet):
self.v1 = nouveauSommet
elif(self.v2 == ancienSommet):
self.v2 = nouveauSommet
elif(self.v3 == ancienSommet):
self.v3 = nouveauSommet
else:
raise Exception("Bad vertex" + ancienSommet)
def retrouveArete(self, v1, v2):
'''Méthode qui renvoie le quad-edge d'un triangle ayant deux sommets pour extrêmités'''
e = Triangulation.QuadEdge(None, None, v1, v2)
if(self.e12 == e):
return self.e12
elif(self.e13 == e):
return self.e13
elif(self.e23 == e):
return self.e23
else:
raise Exception("getEdge")
def remplaceArete(self, ancienneArete, nouvelleArete):
'''Méthode qui substitue le quad-edge d'un triangle par un autre'''
if(self.e12 == ancienneArete):
self.e12 = nouvelleArete
elif(self.e13 == ancienneArete):
self.e13 = nouvelleArete
elif(self.e23 == ancienneArete):
self.e23 = nouvelleArete
else:
raise Exception("changeEdge")
def construitTriangleInitial(self):
'''Méthode qui construit une triangulation initiale qui contient tous les sommets'''
xmin = sys.float_info.max
xmax = sys.float_info.min
ymin = sys.float_info.max
ymax = sys.float_info.min
for v in self.graphe.sommets:
if(v.x() > xmax):
xmax = v.x()
if(v.x() < xmin):
xmin = v.x()
if(v.y() > ymax):
ymax = v.y()
if(v.y() < ymin):
ymin = v.y()
largeur = xmax - xmin
hauteur = ymax - ymin
margex = 0.1 * largeur
margey = 0.1 * hauteur
v1 = self.graphe.ajouteSommet(
xmin - largeur / 2 - margex, ymin - margey)
v2 = self.graphe.ajouteSommet(
xmax + largeur / 2 + margex, ymin - margey)
v3 = self.graphe.ajouteSommet(
(xmin + xmax) / 2, ymax + hauteur + margey)
self.racine = Triangulation.Triangle(v1, v2, v3)
e12 = Triangulation.QuadEdge(None, self.racine, v1, v2)
e13 = Triangulation.QuadEdge(None, self.racine, v1, v3)
e23 = Triangulation.QuadEdge(None, self.racine, v2, v3)
self.racine.e12 = e12
self.racine.e13 = e13
self.racine.e23 = e23
def supprimeAretes(self):
for s in self.graphe.sommets:
s.aretes.clear()
def construitTriangulationInitiale(self):
self.quadEdges = []
self.construitTriangleInitial()
for v in self.graphe.sommets:
t = self.racine.trouve(v)
if(t != None):
t.t12 = Triangulation.Triangle(t.v1, t.v2, v)
t.t13 = Triangulation.Triangle(t.v1, t.v3, v)
t.t23 = Triangulation.Triangle(t.v2, t.v3, v)
e1v = Triangulation.QuadEdge(t.t12, t.t13, t.v1, v)
e2v = Triangulation.QuadEdge(t.t12, t.t23, t.v2, v)
e3v = Triangulation.QuadEdge(t.t13, t.t23, t.v3, v)
self.quadEdges.append(e1v)
self.quadEdges.append(e2v)
self.quadEdges.append(e3v)
t.t12.e12 = t.e12
t.e12.remplaceFace(t, t.t12)
t.t12.e13 = e1v
t.t12.e23 = e2v
t.t13.e12 = t.e13
t.e13.remplaceFace(t, t.t13)
t.t13.e13 = e1v
t.t13.e23 = e3v
t.t23.e12 = t.e23
t.e23.remplaceFace(t, t.t23)
t.t23.e13 = e2v
t.t23.e23 = e3v
def basculeAretes(self):
pile = []
for qe in self.quadEdges:
pile.append(qe)
while(len(pile) > 0):
e = pile.pop()
f1 = e.f1
f2 = e.f2
if(f1 != None and f2 != None):
v1 = e.v1
v2 = e.v2
v3 = f1.troisiemeSommet(v1, v2)
v4 = f2.troisiemeSommet(v1, v2)
if(not conditionDeDelaunay(v3, v1, v4, v2)):
v1v3 = f1.retrouveArete(v1, v3)
v2v3 = f1.retrouveArete(v2, v3)
v1v4 = f2.retrouveArete(v1, v4)
v2v4 = f2.retrouveArete(v2, v4)
f1.remplaceArete(v2v3, v1v4)
f2.remplaceArete(v1v4, v2v3)
v2v3.remplaceFace(f1, f2)
v1v4.remplaceFace(f2, f1)
f1.remplaceSommet(v2, v4)
f2.remplaceSommet(v1, v3)
e.v1 = v3
e.v2 = v4
pile.append(v1v3)
pile.append(v2v3)
pile.append(v1v4)
pile.append(v2v4)
def construitGrapheDeSortie(self, selectionneArete):
'''Méthode qui construit la triangulation de Delaunay à partir du nuage de points passé au constructeur'''
# Sélectionne les arêtes
graphe = self.graphe
racine = self.racine
for qe in self.quadEdges:
v1 = qe.v1
v2 = qe.v2
if(not (racine.aPourSommet(v1) or racine.aPourSommet(v2))):
v3 = qe.f1.troisiemeSommet(v1, v2)
v4 = qe.f2.troisiemeSommet(v1, v2)
selectionneArete(graphe, v1, v2, v3, v4)
return self.graphe