initial commit
parent
c7cbcbd270
commit
1e9fd89980
@ -1,11 +1,14 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
|
||||
Everyone is permitted to copy and distribute verbatim or modified copies of
|
||||
this license document, and changing it is allowed as long as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
@ -1,2 +1,16 @@
|
||||
# etude_courbe
|
||||
# Étude fonctions
|
||||
|
||||
Permet de générer automatiquement le code LaTeX permettant l'étude d'une courbe.
|
||||
|
||||
## Utilisation
|
||||
|
||||
Exécuter en ligne de commande le script ``etude_fonction`` qui vous demandera un dossier dans lequel mettre les sources LaTeX ainsi que l'expression de la fonction à écrire au format ``Python`` (préfixer par ``sp`` les fonctions usuelles) puis les intervalles sur lesquels la fonction est définie, dérivable et sur lequel vous voulez son tableau de variation. Les intervalles doivent être de la forme ``[a,b]`` ou ``]a,b[`` ou ``[a,b[`` ou ``]a,b]`` avec ``a`` et ``b`` convertibles en flottant ou bien les symboles ``-oo`` ou ``oo``.
|
||||
|
||||
Vous obtiendrez alors le ``main.tex`` du dossier voulu que vous pourrez compiler. Pour ajouter des informations, éditer simplement le fichier ``example.tex``. Pour éditer l'en-tête, il suffit d'éditer le fichier ``Utils/02_config_paquets.tex``.
|
||||
|
||||
## Contributions
|
||||
|
||||
Toute contribution est la bienvenue, et peut m'être adressée à l'adresse <math@denoncin.fr>
|
||||
|
||||
## Licence
|
||||
[WTFPL](http://www.wtfpl.net/)
|
||||
|
@ -0,0 +1,5 @@
|
||||
## TODO
|
||||
|
||||
Faire une documentation correcte...
|
||||
|
||||
Écrire des tests ?
|
@ -0,0 +1 @@
|
||||
from etude_courbe.etude_courbe import *
|
@ -0,0 +1 @@
|
||||
version = '0.4'
|
@ -0,0 +1,106 @@
|
||||
from . import lib_etude_courbe as libec
|
||||
import libargfunc as libargv
|
||||
import os
|
||||
import libcurses as curses
|
||||
from sys import argv,exit
|
||||
import documentex
|
||||
from subprocess import call
|
||||
from pylatex import Document, Section, Itemize, Command, Math, NoEscape
|
||||
from pylatex.base_classes import Arguments
|
||||
from sympy import oo
|
||||
|
||||
def etude_courbe():
|
||||
|
||||
if len(argv) != 2:
|
||||
print("usage : etude_courbe nom_dossier")
|
||||
exit(1)
|
||||
|
||||
dossier = argv[1]
|
||||
|
||||
ok = False
|
||||
while not ok:
|
||||
x = curses.saisie_message_std('x(t)= ? ')
|
||||
x, ok = libargv.sympify(x)
|
||||
if not ok:
|
||||
curses.afficher_message_std(x)
|
||||
# en sortie, expression est une expression sympy utilisable
|
||||
ok = False
|
||||
while not ok:
|
||||
y = curses.saisie_message_std('y(t)= ? ')
|
||||
y, ok = libargv.sympify(y)
|
||||
if not ok:
|
||||
curses.afficher_message_std(y)
|
||||
|
||||
ok = False
|
||||
while not ok:
|
||||
intervalle_etude = curses.saisie_message_std("intervalle d'étude ? ")
|
||||
intervalle_etude, ok = libargv.sympify_intervalle(intervalle_etude)
|
||||
if not ok:
|
||||
curses.afficher_message_std(intervalle_etude)
|
||||
|
||||
develop = ( curses.saisie_message_std("Voulez-vous également l'étude et le tracé de la développée ? (o/n) ") == 'o' )
|
||||
|
||||
f = libec.courbe(x,y,intervalle_etude)
|
||||
|
||||
xmin=-10
|
||||
xmax=10
|
||||
ymin=-10
|
||||
ymax=10
|
||||
if f.i.inf != -oo:
|
||||
tmin = round(float(f.i.inf),2)
|
||||
else:
|
||||
tmin = -10
|
||||
if f.i.sup != oo:
|
||||
tmax = round(float(f.i.sup),2)
|
||||
else:
|
||||
tmax = 10
|
||||
|
||||
numero=str(1)
|
||||
numerodev=str(int(numero)+1)
|
||||
call(['documentex',dossier,'doc'])
|
||||
currdir = os.getcwd()
|
||||
os.chdir(os.path.join(dossier))
|
||||
f.graphe(xmin,xmax,ymin,ymax,tmin,tmax,n=1000)
|
||||
if develop:
|
||||
dev = f.developpee()
|
||||
libec.graphe([f,dev],xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf='courbe_dev.pdf',show=False)
|
||||
os.chdir(currdir)
|
||||
|
||||
|
||||
doc = Section(NoEscape(r"\'Etude d'une courbe"))
|
||||
doc.append("Nous étudions la courbe donnée par")
|
||||
doc.append(f.latex_print())
|
||||
doc.append("Les fonctions de coordonnées sont dérivables et données par")
|
||||
doc.append(f.df().latex_print("'"))
|
||||
tableau_variation = f.tikztabvar()
|
||||
if tableau_variation:
|
||||
doc.append("On en déduit le tableau de variation suivant")
|
||||
doc.append(tableau_variation)
|
||||
etude,var = f.points_particuliers()
|
||||
if var:
|
||||
doc.append("De ce tableau de variations on déduit les informations suivantes")
|
||||
doc.append(etude)
|
||||
else:
|
||||
doc.append("<+sympy.solve et sympy.solveset sont malheureusement incapables de trouver les points critiques des fonctions de coordonnées pour une raison qui m'échappe+>")
|
||||
doc.append(NoEscape(r"Le graphique de la courbe est donné sur la figure \ref{fig:"+numero+"}"))
|
||||
doc.append(f.display_graphe(r'Graphique de la courbe',numero))
|
||||
if develop:
|
||||
doc.append(r'La courbure de la courbe est donnée par')
|
||||
with doc.create(Math(escape=False)) as courbure:
|
||||
courbure.append(libec.latex(f.courbure()))
|
||||
doc.append(r'Sa développée est alors donnée par')
|
||||
doc.append(dev.latex_print("_d"))
|
||||
doc.append(r"L'étude de la développée donne alors le tableau de variation suivant")
|
||||
tabvardev = dev.tikztabvar(der="_d")
|
||||
if tabvardev:
|
||||
doc.append(tabvardev)
|
||||
etude,var = dev.points_particuliers()
|
||||
if var:
|
||||
doc.append("On a alors les informations suivantes")
|
||||
doc.append(etude)
|
||||
else:
|
||||
doc.append("<+sympy.solve et sympy.solveset sont malheureusement incapables de trouver les points critiques des fonctions de coordonnées pour une raison qui m'échappe+>")
|
||||
doc.append(NoEscape(r"On peut alors représenter sur un même graphique la courbe et sa développée, voir figure \ref{fig:"+numerodev+"}"))
|
||||
doc.append(libec.display_graphe([f,dev],r'La courbe et sa développée',numerodev,nom_pdf='courbe_dev.pdf'))
|
||||
# doc.append(display_graphe([f],r'La courbe',numerodev,xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf='courbe_dev.pdf',show=False))
|
||||
doc.generate_tex(os.path.join(dossier,'example'))
|
@ -0,0 +1,488 @@
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
from pylatex import Itemize, Command, NoEscape, Alignat
|
||||
from pylatex.base_classes import Arguments, Environment, Options
|
||||
from sympy import Matrix,simplify,latex,diff,oo,limit,FiniteSet,lambdify,degree,S,det,sqrt
|
||||
from sympy.abc import t,x
|
||||
from numpy import linspace
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
from etude_fonction.lib_etude_fonction import Fonction, float_or_tex, order
|
||||
|
||||
|
||||
|
||||
#classes utiles pour les environnements latex utilisés
|
||||
class Array(Environment):#,options=None,Arguments=None,start_arguments=None,):
|
||||
escape=False
|
||||
class Displaymath(Environment):
|
||||
escape=False
|
||||
class Figure(Environment):
|
||||
escape=False
|
||||
class Tikzpicture(Environment):
|
||||
escape=False
|
||||
class Cases(Environment):
|
||||
escape=False
|
||||
class Pmatrix(Environment):
|
||||
escape=False
|
||||
|
||||
def pmatrix(liste):
|
||||
"""
|
||||
remplit le vecteur colonne à partir d'une liste de chaînes de caractères
|
||||
"""
|
||||
matrix=Pmatrix()
|
||||
n = len(liste)
|
||||
for i in range(n):
|
||||
element = liste[i]
|
||||
if i!=n-1:
|
||||
matrix.append(NoEscape(element + r"\\"))
|
||||
else:
|
||||
matrix.append(NoEscape(element))
|
||||
return matrix
|
||||
|
||||
def norme(x,y):
|
||||
"""
|
||||
retourne la norme euclidienne du vecteur de coordonnées (x,y)
|
||||
"""
|
||||
return sqrt(x**2+y**2)
|
||||
|
||||
class courbe():
|
||||
"""
|
||||
classe permettant d'étudier/tracer des courbes pas trop compliquées du plan. À améliorer :
|
||||
- ajouter l'étude d'asymptotes
|
||||
- problème avec la résolution de sinh=0 traitée pour le moment de façon ad hoc uniquement sur les abscisses
|
||||
- renvoyer des string plutôt que faire des print
|
||||
- conversion radian-degré pour les fonctions trigo réciproques
|
||||
- ajouter des tangentes sur le graphique
|
||||
"""
|
||||
def __init__(self,x,y,i):
|
||||
"""
|
||||
Une courbe est l'ensemble des deux fonctions coordonnées et d'un Interval. Elle doit être continue sur cet l'intervalle correspondant.
|
||||
"""
|
||||
self.x=x
|
||||
self.y=y
|
||||
self.i=i #i est un intervalle
|
||||
def __str__(self):
|
||||
return str(self.x)+','+str(self.y)+','+str(self.i)
|
||||
def latex_print(self,der=''):
|
||||
"""
|
||||
Permet de donner le code latex représentant la courbe par ses fonctions coordonnées. der est en général un '
|
||||
"""
|
||||
align = Alignat(escape=False,numbering=False)
|
||||
with align.create(Cases()) as cas:
|
||||
cas.append(NoEscape(r"x"+der+"(t)&="+latex(self.x)+r"\\"))
|
||||
cas.append(NoEscape(r"y"+der+"(t)&="+latex(self.y)+r"\\"))
|
||||
return align
|
||||
def fx(self):
|
||||
return Fonction(self.x,self.i,S.Reals)
|
||||
def fy(self):
|
||||
return Fonction(self.y,self.i,S.Reals)
|
||||
def subs(self,symbol):
|
||||
return courbe(self.x.subs(t,symbol),self.y.subs(t,symbol),self.i)
|
||||
def dx(self):
|
||||
"""
|
||||
retourne sous forme d'expression symbolique la dérivée de la première fonction coordonnée
|
||||
"""
|
||||
return diff(self.x,t).simplify()
|
||||
def dy(self):
|
||||
"""
|
||||
retourne sous forme d'expression symbolique la dérivée de la deuxième fonction coordonnée
|
||||
"""
|
||||
return diff(self.y,t).simplify()
|
||||
def df(self):
|
||||
"""
|
||||
retourne sous forme d'une courbe la dérivée de la courbe
|
||||
"""
|
||||
return courbe(self.dx(),self.dy(),self.i)
|
||||
def courbure(self):
|
||||
"""
|
||||
Retourne la courbure en un point birégulier comme le déterminant de vitesse accélération divisé par la norme de la vitesse au cube
|
||||
"""
|
||||
vitesse = self.df()
|
||||
acceleration = vitesse.df()
|
||||
numerateur = det(Matrix([[vitesse.x,acceleration.x],[vitesse.y,acceleration.y]]))
|
||||
denominateur = (norme(vitesse.x,vitesse.y).simplify())**3
|
||||
return (numerateur/denominateur).simplify()
|
||||
def rayon_courbure(self):
|
||||
"""
|
||||
nom trompeur, c'est en fait le rapport lambda(t) tel que le point (x(t),y(t))+lambda(t) (-y'(t),x(t)) soit la développée de la courbe
|
||||
"""
|
||||
return ((self.dx())**2+(self.dy())**2).simplify()/det(Matrix([[self.dx(),self.df().dx()],[self.dy(),self.df().dy()]])).simplify()
|
||||
def developpee(self):
|
||||
"""
|
||||
retourne sous forme de courbe la développée de la courbe initiale
|
||||
"""
|
||||
return courbe((self.x-self.rayon_courbure()*self.dy()).simplify(),(self.y+self.rayon_courbure()*self.dx()).simplify(),self.i)
|
||||
def graphe(self,xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf='courbe.pdf',n=1000):
|
||||
"""
|
||||
trace le graphique de la courbe et le sauvegarde dans le dossier courant sous le nom courbe.pdf
|
||||
"""
|
||||
ax=plt.gca()
|
||||
ax.axis((xmin,xmax,ymin,ymax))
|
||||
ax.set_aspect('equal')
|
||||
ax.spines['right'].set_color('none')
|
||||
ax.spines['top'].set_color('none')
|
||||
ax.xaxis.set_ticks_position('bottom')
|
||||
ax.spines['bottom'].set_position(('data',0))
|
||||
ax.yaxis.set_ticks_position('left')
|
||||
ax.spines['left'].set_position(('data',0))
|
||||
fx=lambdify((t),self.x,'numpy')
|
||||
fy=lambdify((t),self.y,'numpy')
|
||||
T=linspace(tmin,tmax,n)
|
||||
X=[fx(t) for t in T]
|
||||
Y=[fy(t) for t in T]
|
||||
plt.plot(X,Y)
|
||||
plt.savefig(nom_pdf)
|
||||
def display_graphe(self,titre,numero,nom_pdf='courbe.pdf',position='H'):
|
||||
#self.graphe(xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf=nom_pdf,n=1000)
|
||||
graphique = Figure(options=Options('H'))
|
||||
graphique.append(r'\centering')
|
||||
graphique.append(Command('includegraphics',arguments=Arguments(nom_pdf)))
|
||||
arg = Arguments(NoEscape(titre+r'\label{fig:'+numero+'}'))
|
||||
# arg.append(Command('label',arguments=Arguments('fig:'+numero)))
|
||||
c = Command('caption',arguments=arg)
|
||||
graphique.append(c)
|
||||
return graphique
|
||||
|
||||
def series_latex(self,x0=0,n=3,dir='+',logx=None):
|
||||
"""
|
||||
retourne le code latex d'un développement limité de la courbe avec au moins trois termes non nuls.
|
||||
"""
|
||||
dlx = self.x.series(t,x0,n=None)
|
||||
dly = self.y.series(t,x0,n=None)
|
||||
dlxlist = []
|
||||
dlylist = []
|
||||
for i in range(n):
|
||||
try:
|
||||
ndlx = next(dlx)
|
||||
try:
|
||||
dlxlist+= [[ndlx/(t-x0)**degree(ndlx,t),degree(ndlx,t)]]
|
||||
except:
|
||||
dlxlist+= [[ndlx,0]]
|
||||
except StopIteration:
|
||||
#print('pas de terme après le '+str(i+1)+'ème')
|
||||
dlxlist+=[[0,degx+1]] ##suppose que la boucle fonctionne toujours au moins une fois sous peine de degx undefined global variable
|
||||
try:
|
||||
ndly = next(dly)
|
||||
try:
|
||||
dlylist+= [[ndly/(t-x0)**degree(ndly,t),degree(ndly,t)]]
|
||||
except:
|
||||
dlylist+= [[ndly,0]]
|
||||
except StopIteration:
|
||||
#print('pas de terme après le '+str(i+1)+'ème')
|
||||
dlylist+=[[0,degy+1]]
|
||||
degx = dlxlist[-1][1]
|
||||
degy = dlylist[-1][1]
|
||||
# try: ### avant modif
|
||||
# ndlx = next(dlx)
|
||||
# ndly = next(dly)
|
||||
# try:
|
||||
# dlxlist+= [[ndlx/(t-x0)**degree(ndlx,t),degree(ndlx,t)]]
|
||||
# except:
|
||||
# dlxlist+= [[ndlx,0]]
|
||||
# try:
|
||||
# dlylist+= [[ndly/(t-x0)**degree(ndly,t),degree(ndly,t)]]
|
||||
# except:
|
||||
# dlylist+= [[ndly,0]]
|
||||
# except StopIteration:
|
||||
# print('pas de terme après le '+str(i+1)+'ème')
|
||||
# break
|
||||
|
||||
align = Alignat(escape=False,numbering=False)
|
||||
with align.create(Pmatrix()) as matrix:
|
||||
matrix.append(NoEscape(r"x(t)\\ y(t)"))
|
||||
align.append(NoEscape(r"="))
|
||||
l=len(dlxlist)
|
||||
i=0
|
||||
while len(dlxlist)>0 and len(dlylist)>0:
|
||||
if dlxlist[i][1]<dlylist[i][1]:
|
||||
degre=dlxlist[i][1]
|
||||
if dlxlist[i][1]==0:
|
||||
align.append(pmatrix([latex(dlxlist[i][0]),r"0"]))
|
||||
align.append(NoEscape(r"+"))
|
||||
else:
|
||||
align.append(pmatrix([latex(dlxlist[i][0]),r"0"]))
|
||||
if x0==0:
|
||||
align.append(NoEscape(r"t^{"+latex(dlxlist[i][1])+'}+'))
|
||||
else:
|
||||
align.append(NoEscape(r"\left(t-"+latex(x0)+r'\right)^{'+latex(dlxlist[i][1])+'}+'))
|
||||
dlxlist.pop(0)
|
||||
elif dlxlist[i][1]>dlylist[i][1]:
|
||||
degre=dlylist[i][1]
|
||||
if dlylist[i][1]==0:
|
||||
align.append(pmatrix([r"0",latex(dlylist[i][0])]))
|
||||
align.append(NoEscape(r"+"))
|
||||
else:
|
||||
align.append(pmatrix([r"0",latex(dlylist[i][0])]))
|
||||
if x0==0:
|
||||
align.append(NoEscape(r"t^{"+latex(dlylist[i][1])+'}+'))
|
||||
else:
|
||||
align.append(NoEscape(r"\left(t-"+latex(x0)+r'\right)^{'+latex(dlylist[i][1])+'}+'))
|
||||
dlylist.pop(0)
|
||||
else:
|
||||
degre=dlxlist[i][1]
|
||||
if dlylist[i][1]==0:
|
||||
align.append(pmatrix([latex(dlxlist[i][0]),latex(dlylist[i][0])]))
|
||||
align.append(r"+")
|
||||
else:
|
||||
align.append(pmatrix([latex(dlxlist[i][0]),latex(dlylist[i][0])]))
|
||||
if x0==0:
|
||||
align.append(NoEscape(r't^{'+latex(dlylist[i][1])+'}+'))
|
||||
else:
|
||||
align.append(NoEscape(r"\left(t-"+latex(x0)+r'\right)^{'+latex(dlylist[i][1])+'}+'))
|
||||
dlylist.pop(0)
|
||||
dlxlist.pop(0)
|
||||
if x0==0:
|
||||
align.append(NoEscape(r'o\left(t^{'+latex(degre)+r'}\right)'))
|
||||
else:
|
||||
align.append(NoEscape(r'o\left(\left(t-'+latex(x0)+r'\right)^{'+latex(degre)+r'}\right)'))
|
||||
return align
|
||||
def indices_fondamentaux(self,x0=0):
|
||||
"""
|
||||
renvoie une liste comportant 0, 1 ou les deux premiers indices fondamentaux et un message d'erreur s'il n'est pas possible d'obtenir les deux premiers indices fondamentaux.
|
||||
"""
|
||||
dlx = self.x.series(t,x0,n=None)
|
||||
dly = self.y.series(t,x0,n=None)
|
||||
dlxlist = []
|
||||
dlylist = []
|
||||
for i in range(3):
|
||||
try:
|
||||
ndlx = next(dlx)
|
||||
try:
|
||||
dlxlist+= [[ndlx/(t-x0)**degree(ndlx,t),degree(ndlx,t)]]
|
||||
except:
|
||||
dlxlist+= [[ndlx,0]]
|
||||
except StopIteration:
|
||||
#print('pas de terme après le '+str(i+1)+'ème')
|
||||
dlxlist+=[[0,degx+1]] ##suppose que la boucle fonctionne toujours au moins une fois sous peine de degx undefined global variable
|
||||
try:
|
||||
ndly = next(dly)
|
||||
try:
|
||||
dlylist+= [[ndly/(t-x0)**degree(ndly,t),degree(ndly,t)]]
|
||||
except:
|
||||
dlylist+= [[ndly,0]]
|
||||
except StopIteration:
|
||||
#print('pas de terme après le '+str(i+1)+'ème')
|
||||
dlylist+=[[0,degy+1]]
|
||||
degx = dlxlist[-1][1]
|
||||
degy = dlylist[-1][1]
|
||||
|
||||
dlxlist = [item[1] for item in dlxlist]
|
||||
dlylist = [item[1] for item in dlylist]
|
||||
# for i in range(3):
|
||||
# try:
|
||||
# ndlx = next(dlx)
|
||||
# ndly = next(dly)
|
||||
# try:
|
||||
# dlxlist+= [degree(ndlx,t)]
|
||||
# except:
|
||||
# dlxlist+= [0]
|
||||
# try:
|
||||
# dlylist+= [degree(ndly,t)]
|
||||
# except:
|
||||
# dlylist+= [0]
|
||||
# except StopIteration:
|
||||
# print('pas de terme après le '+str(i+1)+'ème')
|
||||
# break
|
||||
indices=[]
|
||||
while len(indices)<2:
|
||||
try:
|
||||
if dlxlist[0]<dlylist[0]:
|
||||
if dlxlist[0]>0:
|
||||
indices.append(dlxlist[0])
|
||||
dlxlist.pop(0)
|
||||
else:
|
||||
dlxlist.pop(0)
|
||||
elif dlylist[0]<dlxlist[0]:
|
||||
if dlylist[0]>0:
|
||||
indices.append(dlylist[0])
|
||||
dlylist.pop(0)
|
||||
else:
|
||||
dlylist.pop(0)
|
||||
else:
|
||||
if dlylist[0]>0:
|
||||
indices.append(dlylist[0])
|
||||
dlylist.pop(0)
|
||||
dlxlist.pop(0)
|
||||
else:
|
||||
dlylist.pop(0)
|
||||
dlxlist.pop(0)
|
||||
except:
|
||||
break
|
||||
return indices
|
||||
def type_point(self,x0=0):
|
||||
"""
|
||||
utilise les deux indices fondamentaux pour renvoyer le type de point sous forme de chaine de caractère, ou un message expliquant qu'il n'y a pas assez d'informations pour conclure.
|
||||
"""
|
||||
indices = self.indices_fondamentaux(x0)
|
||||
if len(indices)==2:
|
||||
if indices[0]%2==1 and indices[1]%2==0:
|
||||
if indices[0]==1 and indices[1]==2:
|
||||
return "point birégulier"
|
||||
else:
|
||||
return "point ordinaire"
|
||||
if indices[0]%2==1 and indices[1]%2==1:
|
||||
return "point d'inflexion"
|
||||
if indices[0]%2==0 and indices[1]%2==1:
|
||||
return "point de rebroussement de première espèce"
|
||||
if indices[0]%2==0 and indices[1]%2==0:
|
||||
return "point de rebroussement de deuxième espèce"
|
||||
else:
|
||||
return "point pour lequel il n'y a pas assez d'informations pour conclure"
|
||||
def set_solf(self):
|
||||
"""
|
||||
retourne les zéros des dérivées de la fonction vectorielle f de la variable t ainsi que les bornes de son intervalle de définition
|
||||
"""
|
||||
f = self.subs(x)
|
||||
critiquex = f.fx().critique(f.fx().s)
|
||||
critiquey = f.fy().critique(f.fy().s)
|
||||
if critiquex==-1 or critiquey==-1:
|
||||
return -1
|
||||
else:
|
||||
return critiquex.union(critiquey).intersection(self.i).union(FiniteSet(self.i.sup)).union(FiniteSet(self.i.inf))
|
||||
def intervalle_tabvar(self):
|
||||
"""
|
||||
donne le code latex de la première ligne d'un tableau de variation de f
|
||||
"""
|
||||
set_sol=self.set_solf()
|
||||
try:
|
||||
set_sol=order(set_sol)
|
||||
sol=''
|
||||
for s in set_sol:
|
||||
if s == oo:
|
||||
sol+='$'
|
||||
sol+='+'+latex(s)
|
||||
sol+='$'
|
||||
elif s == set_sol[-1]:
|
||||
sol+='$'
|
||||
sol+=latex(s)
|
||||
sol+='$'
|
||||
else:
|
||||
sol+='$'
|
||||
sol+=latex(s)
|
||||
sol+='$,'
|
||||
return sol
|
||||
except:
|
||||
return -1
|
||||
def signes(self,fun,eps=10**(-1)):
|
||||
"""
|
||||
fonction permettant de remplir avec tikz un tableau de signes : on trouve les valeurs intéressantes de la courbe, celles d'une des fonction de coordonnées et on établit un tableau de signe en remplissant deux cases de suite grâce à la fonction signe en partant d'une valeur intéressante de la courbe (borne ou zéro d'une des dérivées).
|
||||
"""
|
||||
try:
|
||||
set_sol=order(self.set_solf())
|
||||
set_solfu=order(fun.subs(t,x).critique(fun.s))
|
||||
signx=''
|
||||
n=len(set_sol)
|
||||
for i in range(n-1):
|
||||
sol1=set_sol[i]
|
||||
sol2=set_sol[i+1]
|
||||
signx+=fun.subs(t,x).dx(self.i).signe(eps,sol1,sol2,set_solfu)
|
||||
sol=set_sol[n-1]
|
||||
if sol in set_solfu:
|
||||
signx+='0'
|
||||
return signx
|
||||
except:
|
||||
return -1
|
||||
def variations(self,fun,eps=10**(-1)):
|
||||
"""
|
||||
donne le code latex pour la ligne du tableau de variations d'une des fonctions de coordonnées en utilisant la fonction variation
|
||||
"""
|
||||
var=''
|
||||
func = Fonction(fun.expr.subs(t,x),fun.s,fun.t)
|
||||
set_sol = order(self.set_solf())
|
||||
n=len(set_sol)
|
||||
set_solfu = order(func.critique(func.s))
|
||||
for i in range(n-1):
|
||||
sol1=set_sol[i]
|
||||
sol2=set_sol[i+1]
|
||||
var+=func.variation(func.s,sol1,sol2,set_solfu,eps)
|
||||
sol1=set_sol[n-2]
|
||||
sol2=set_sol[n-1]
|
||||
lim = limit(fun.expr,t,sol2,'-')
|
||||
tex_lim = float_or_tex(lim)
|
||||
# dfun = func.dx(func.s)
|
||||
funx = (fun.subs(t,x)).dx(fun.s)
|
||||
signeligne = funx.signe(eps,sol1,sol2,set_solfu)
|
||||
if '+' in signeligne:
|
||||
var+='+/$'+tex_lim+'$'
|
||||
elif '-' in signeligne:
|
||||
var+='-/$'+tex_lim+'$'
|
||||
return var
|
||||
def tikztabvar(self,der='',eps=10**(-1)):
|
||||
"""
|
||||
donne le code latex pour remplir le tableau de signes/variations de la courbe f ou une chaîne vide si cela n'est pas possible
|
||||
"""
|
||||
figure = Figure(options=Options('H'))
|
||||
figure.append(Command('centering'))
|
||||
try:
|
||||
with figure.create(Tikzpicture()) as fig:
|
||||
fig.append(Command('tkzTabInit',arguments=Arguments(NoEscape("$t$/1,$x"+der+"'(t)$/1,$x"+der+"$/1,$y"+der+"'(t)$/1,$y"+der+"$/1"),NoEscape(self.intervalle_tabvar()))))
|
||||
fig.append(Command('tkzTabLine',arguments=Arguments(NoEscape(self.signes(self.fx(),eps)))))
|
||||
fig.append(Command('tkzTabVar',arguments=Arguments(NoEscape(self.variations(self.fx(),eps)))))
|
||||
fig.append(Command('tkzTabLine',arguments=Arguments(NoEscape(self.signes(self.fy(),eps)))))
|
||||
fig.append(Command('tkzTabVar',arguments=Arguments(NoEscape(self.variations(self.fy(),eps)))))
|
||||
return figure
|
||||
except: # problème dans l'étude des signes ou des variations
|
||||
return ''
|
||||
def points_particuliers(self):
|
||||
"""
|
||||
génère le code latex décrivant la nature des points en lesquels il y a une tangente horizontale ou verticale, ainsi que la nature des points stationnaires en justifiant avec un développement limité.
|
||||
"""
|
||||
set_sol = order(self.set_solf())
|
||||
set_solx = order(self.fx().subs(t,x).critique(self.fx().s))
|
||||
set_soly = order(self.fy().subs(t,x).critique(self.fy().s))
|
||||
var = 0
|
||||
etude = Itemize()
|
||||
for s in set_sol:
|
||||
if s in set_solx and s not in set_soly:
|
||||
etude.add_item(NoEscape(r'il y a une tangente verticale au point de paramètre $'+ latex(s)+'$'))
|
||||
var=1
|
||||
elif s in set_soly and not s in set_solx:
|
||||
etude.add_item(NoEscape(r'il y a une tangente horizontale au point de paramètre $'+latex(s)+'$'))
|
||||
var=1
|
||||
elif s in set_soly and s in set_soly:
|
||||
string = r'le point de paramètre $'+latex(s)+'$ est un '+self.type_point(s)
|
||||
string += r' comme le montre de développement limité suivant au voisinage de $'+latex(t)+'='+latex(s)+'$\n'
|
||||
# string += self.series_latex()
|
||||
etude.add_item(NoEscape(string))
|
||||
etude.append(self.series_latex(s))
|
||||
var=1
|
||||
return [etude,var]
|
||||
|
||||
|
||||
|
||||
def graphe(liste,xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf='courbe.pdf',n=1000,show=True):
|
||||
"""
|
||||
trace sur un même graphique les courbes de la liste
|
||||
"""
|
||||
ax=plt.gca()
|
||||
ax.axis((xmin,xmax,ymin,ymax))
|
||||
ax.set_aspect('equal')
|
||||
ax.spines['right'].set_color('none')
|
||||
ax.spines['top'].set_color('none')
|
||||
ax.xaxis.set_ticks_position('bottom')
|
||||
ax.spines['bottom'].set_position(('data',0))
|
||||
ax.yaxis.set_ticks_position('left')
|
||||
ax.spines['left'].set_position(('data',0))
|
||||
for arc in liste:
|
||||
fx=lambdify((t),arc.x,'numpy')
|
||||
fy=lambdify((t),arc.y,'numpy')
|
||||
T=linspace(tmin,tmax,n)
|
||||
X=[fx(t) for t in T]
|
||||
Y=[fy(t) for t in T]
|
||||
plt.plot(X,Y)
|
||||
if show:
|
||||
plt.show()
|
||||
plt.savefig(nom_pdf)
|
||||
|
||||
def display_graphe(liste,titre,numero,nom_pdf='courbe.pdf',position='H'):
|
||||
"""
|
||||
Renvoie le code latex pour afficher les courbes de la liste
|
||||
"""
|
||||
#graphe(liste,xmin,xmax,ymin,ymax,tmin,tmax,nom_pdf=nom_pdf,n=n,show=show)
|
||||
graphique = Figure(options=Options('H'))
|
||||
graphique.append(r'\centering')
|
||||
graphique.append(Command('includegraphics',arguments=Arguments(NoEscape(nom_pdf))))
|
||||
arg = Arguments(NoEscape(titre+r'\label{fig:'+numero+'}'))
|
||||
c = Command('caption',arguments=arg)
|
||||
graphique.append(c)
|
||||
return graphique
|
@ -0,0 +1,31 @@
|
||||
from setuptools import setup, find_packages
|
||||
from etude_courbe.constantes_etude_courbe import version
|
||||
|
||||
setup(
|
||||
name="etude_courbe",
|
||||
version=version,
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'etude_courbe = etude_courbe.etude_courbe:etude_courbe',
|
||||
]
|
||||
},
|
||||
install_requires=["libcurses",
|
||||
"libargfunc",
|
||||
"etude_fonction",
|
||||
"documentex",
|
||||
"sympy",
|
||||
"pylatex",
|
||||
"matplotlib",
|
||||
"numpy",
|
||||
],
|
||||
|
||||
author="David Denoncin",
|
||||
author_email="math@denoncin.fr",
|
||||
url="math.denoncin.fr",
|
||||
description="Génération de corrigés d'étude de courbes",
|
||||
classifiers=[
|
||||
"Licence :: WTFPL"
|
||||
]
|
||||
)
|
Loading…
Reference in New Issue