Python pour le calcul scientifique Exercices

publicité
Python pour le calcul scientifique
Exercices
Pierre Navaro - IRMAR
ENSAI le 25 mars 2016
1
1.1
Programmation Python
Une fonction pour calculer la norme
>>> def norme(a,b):
""" calcul de la norme """
...
return sqrt(a*a+b*b)
>>> from math import *
>>> norme(3,4)
5.0
>>> help(norme)
Help on function norme in module __main__:
norme(a, b)
calcul de la norme
(END)
Récrire cette fonction avec en entrée une liste python de taille quelconque.
1.2
Ecrire et lire un fichier avec le module pickle
>>> import pickle
>>> l=["camembert","coulommiers","brie"]
>>> f=open("fromages","w")
>>> pickle.dump(l,f)
>>> f.close()
>>> f=open("fromages","r")
>>> lr=pickle.load(f)
>>> f.close()
>>> print lr
['camembert', 'coulommiers', 'brie']
Ajouter "munster" et "neuchatel" à la liste, trier la liste dans l’ordre alphabétique et
modifier le fichier "fromages".
1.3
Programmation Objet
Créer une classe Python nommée Vecteur, que l’on utilisera pour décrire un vecteur plan. Ces paramètres sont x et y . Implémenter l’addition __add__, la soustraction
1
__sub__, la multiplication __mul__ par un vecteur ou un scalaire et la représentation
__repr__. Ne pas oublier le constructeur __init__.
Attention votre multiplication n’est pas commutative par défaut, il faut implémenter
la méthode __rmul__.
Créer une classe nommée Particule, dont les paramètres sont les vecteurs position
et vitesse. Implémenter une méthode "deplace(dt)" pour calculer la nouvelle position
d’une particule après un pas de temps dt. Créer ensuite une classe Ion dérivant de
Particule avec un paramètre supplémentaire "masse".
>>> xp = Vecteur(3,4)
>>> vp = Vecteur(1,2)
>>> p = Particule(xp,vp)
>>> p
position (3 , 4); vitesse (1 , 2)
>>> p.deplace(1.)
>>> p
position (4.0 , 6.0); vitesse (1 , 2)
>>> i = Ion(xp,vp,1.)
>>> i.deplace(-1.)
>>> i
position (2.0 , 2.0); vitesse (1 , 2)
>>> i.energie
2.5
2
Numpy
2.1
Création d’un tableau numpy
Créer les tableaux suivants :
[100 101 102 103 104 105 106 107 108 109]
avec numpy.arange
[-2. -1.8 -1.6 -1.4 -1.2 -1. -0.8 -0.6 -0.4 -0.2 0.
0.2 0.4 0.6 0.8 1. 1.2 1.4 1.6 1.8]
avec numpy.linspace
[[ 0.001
0.00129155 0.0016681 0.00215443 0.00278256
0.003593810.00464159 0.00599484 0.00774264 0.01]
avec numpy.logspace
[[
[
[
[
[
[
[
0.
0.
0.
0.
0.
0.
0.
0. -1. -1. -1.]
0. 0. -1. 1.]
0. 0. 0. -1.]
0. 0. 0. 0.]
0. 0. 0. 0.]
0. 0. 0. 0.]
0. 0. 0. 0.]]
2
avec numpy.tri, numpy.zeros, numpy.transpose
[[ 0. 1. 2. 3.
[-1. 0. 1. 2.
[-1. -1. 0. 1.
[-1. -1. -1. 0.
[-1. -1. -1. -1.
4.]
3.]
2.]
1.]
0.]]
avec numpy.ones, numpy.diag
2.2
Copie et référence
Exécuter les scripts python suivants, quel est le problème ? comment le résoudre ?
a = np.ones((4,3))
b = a.transpose()
b[0,1] = 10
print a
Script : https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex6.py
a = np.arange(12)
b = a.reshape((4,3))
b[0,1] = 10
print a
Script : https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex7.py
2.3
Lire des données issues de fichiers texte
Utiliser la fonction numpy.loadtxt pour charger les données contenues dans le fichier
https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/data8.txt.
Script pour créer le fichier :
https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex8_gen.py
Les donnees contenues dans :
https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/data9.txt
ont été écrites de la manière suivante : La première ligne renseigne le nombre d’éléments pour chaque direction et la deuxième ligne contient les données. Ecrire le programme Python pour lire ces données et initialiser avec elles un tableau numpy 2D.
Script pour créer le fichier de données :
https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex9_gen.py
2.4
Calculer une intégrale
Evaluer l’intégrale suivante :
Z
∞
2
e−v dv
I=
−∞
— Analytiquement avec sympy.
3
>>> from sympy import *
>>> v = symbols('v')
>>> integrate(exp(-v*v),(v,-oo,oo))
pi**(1/2)
— numériquement avec v ∈ [−10; 10] avec la méthode des trapèzes, écrire le code
et tester avec N=20.
— comparer avec le résultat de la fonction numpy.trapz
3
Matplotlib
3.1
Mode interactif
Utiliser ipython -pylab pour exécuter les lignes suivantes :
x = linspace(0,4*pi,1000)
y = sin(x) + 0.2*sin(10*x)
plot(x,y)
xlabel(’x’)
clf()
plot(x,y,label=’hello’)
xlabel(’$x$’)
legend()
title(’\LaTeX fonts like $\mu$ are available’)
tics=arange(0,4*pi+0.1, step=pi/2)
xticks(tics)
tics_label=[’$0$’, ’$\pi/2$’]
xticks(tics,tics_label)
3.2
Mode non interactif
Reproduire le même graphique en insérant les lignes précédentes dans un fichier. Il
existe une variable In dans ipython qui contient toutes les commandes déjà tapées dans
Ipython. La commande "%hist -n" peut vous être utile également.
3.3
Tracer des données lues dans un fichier
Récupérer les données des fichiers :
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/foo_data.txt
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/foo_axis.txt
et tracer les données "data" en fonction des données "axis".
3.4
Tracer des données au format hdf5
Lire les données contenues dans le fichier
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/foo.h5
Tracer "data" en fonction de "axis".
4
import h5py
f = h5py.File(’foo.h5’, ’r’)
x = f[’axis’].value
y = f[’data’].value
f.close()
Script pour créer le fichier de données :
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex5_gendata.
py
3.5
Tracé 2D d’un champ scalaire
Tracer les données nommées "data2d" lue dans le fichier :
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/bar.h5
avec matplotlib.pyplot.contour et matplotlib.pyplot.imshow. Les coordonnées x
et y sont nommées "x_axis" et "y_axis" dans les données hdf5.
Script pour créer le fichier de données :
https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex7_gendata.
py
4
Scipy
4.1
Interpolation
Prenez le fichier https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/
ex1.py.
Comparer les courbes d’interpolations Krogh et Barycentric avec l’interpolation cubique. Utiliser les deux séries de points (x, y1 ) et (x, y2 ) calculées par les lignes python
suivantes :
a=sp.random.rand(10)-0.5
x=sp.linspace(-1,1,num=10)
y1=(x-1.)*(x-0.5)*(x+0.5)
y2=(x-1.)*(x-0.5)*(x+0.5)+a
4.2
Laplacien en deux dimensions
On considère l’équation du laplacien :
∆u(x, y) = f (x, y),
Afin que le problème soit bien posé, on spécifie des conditions aux limites sur le bord
du domaine de type Dirichlet (u(x, y, t) connue sur le bord).
Discrétisation spatiale : on utilise des différences finies d’ordre 2 et un maillage
composé de Nx × Ny rectangles de taille ∆x × ∆y .
ui,j−1 − 2uij + uij+1
ui−1,j − 2uij + ui+1j
+
= fij
2
∆x
∆y 2
5
4.3
Assemblage de la matrice
Construire la matrice creuse associée à cette discrétisation en tenant compte des
conditions aux bords. Voici un exemple avec la fonction contenue dans :
https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/ComputeMatrix.py
Assemblez la matrice en utilisant scipy.sparse.spdiags.
4.4
Résolution du problème
Fichier https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/laplacian2d.
py
Pour résoudre le système linéaire, nous avons utiliser la fonction numpy pour matrice pleine. Changer le programme pour utiliser l’algorithme du Gradient Conjugué.
On pourra également utiliser un préconditionneur.
5
Python+Fortran
5.1
Exemple simple d’utilisation de f2py
Soit le fichier fortran suivant pour le calcul de la norme :
https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/norme.f90
Création du module Python :
$wget https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/norme.f90
$f2py -m fortranmod -c norme.f90
Tester dans python :
>>>
>>>
4.0
>>>
5.0
>>>
5.2
import fortranmod
fortranmod.norme(4.)
fortranmod.norme([4,3])
print fortranmod.norme.__doc__
Modification d’un fichier signature : dgemm
Nous allons créer la fonction f2py de DGEMM : la subroutine lapack permettant de
calculer le produit de deux matrices.
Générer votre fichier signature dgemm.pyf :
$wget https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/dgemm.f
$f2py -h dgemm.pyf dgemm.f -m mylapack
Modifier ce fichier pour que cette fonction soit utilisable dans Python avec les lignes
suivantes.
$f2py -c dgemm.pyf -llapack
6
>>> import numpy
>>> import mylapack
>>> a = numpy.array([[7,8],[3,4],[1,2]])
>>> b = numpy.array([[1,2,3],[4,5,6]])
>>> c = mylapack.dgemm(a,b)
>>> print c
[[ 39. 54. 69.]
[ 19. 26. 33.]
[ 9. 12. 15.]]
5.3
Création d’une fonction F2PY pour le solveur de Poisson
Utilisons le programme Fortran suivant qui va permettre de calculer le laplacien.
https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/lap2d_fortran.f90
Compilation du module f2py
$ wget https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/lap2d_fortran.f90
$ f2py -c lap2d_fortran.f90 -m fortranmod
On l’utilise pour résoudre l’équation de Poisson à l’aide du script python :
Fichier :https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/laplacian2d_
1.py
$ wget https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/laplacian2d_1.py
$ python laplacian2d_1.py
5.4
Module fortran
A partir du fichier fortran précèdent, créer un module f90 nommé lap2d avec comme
variables globales dx et dy . Modifier le fichier python pour utiliser ce module.
7
6
Interface avec le langage C
6.1
Fonction exponentielle
exp(x) = lim
n→+∞
1+
x n
n
Créer la fonction python exp(x,n) dans un fichier exp_py.py.
def exp(x,n):
"""Fonction exponentielle"""
Pour tester les performances ajouter les lignes suivantes à votre fichier :
if __name__ == '__main__':
from timeit import Timer
t = Timer("exp(1.,50)", "from __main__ import exp")
print "1000000 calls : %s " % (t.timeit())
Puis taper :
$ python exp_py.py
6.2
Fonction C
Créer votre propre fonction C ou utiliser
https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exp_c.c
6.3
C-TYPES
Compiler votre librairie dynamique :
gcc -fPIC -shared -o exp_c.so -O3
exp_c.c
Tester le package ctypes permettant d’appeler cette fonction avec le code suivant
from timeit import Timer
print "Ctypes..."
setup_code = """
from ctypes import CDLL,c_double,c_int
expDLL=CDLL('./exp_c.so')
expDLL.exp_c.restype = c_double
"""
t = Timer("expDLL.exp_c(c_double(1),c_int(50))",setup_code)
print "1,000,000 calls : %s " % t.timeit()
Vous pouvez remarquer les fonctions de conversion C->Python
6.4
SWIG
Créer le fichier d’interface SWIG et générer le module python exp_swig.
8
swig -python exp_c.i
gcc ‘python2.7-config --cflags‘ -fPIC \
-shared -O3 -o _exp_swig.so exp_c_wrap.c exp_c.c
On peut également générer le module en utilisant l’utilitaire scons, éditer un fichier
nommé SConstruct et insérer les lignes suivantes :
import distutils.sysconfig
env = Environment(SWIGFLAGS=['-python'],
CPPPATH=[distutils.sysconfig.get_python_inc()],
SHLIBPREFIX="")
env.SharedLibrary('_exp_swig.so', ['exp_c.c', 'exp_c.i'])
Puis taper :
$ scons
Tester votre appel de fonction dans un fichier python.
print "SWIG..."
t = Timer("exp_swig.exp_c(1.,50)", "import exp_swig")
print "1,000,000 calls : %s " % t.timeit()
6.5
Cython
Transformer la fonction Python en Cython dans le fichier exp_cython.pyx.
Compiler votre module avec le fichier setup.py suivant :
from Cython.Distutils import build_ext
from numpy.distutils.core import Extension, setup
module_cython = Extension('exp_cython',['exp_cython.pyx'])
setup( name='Exponentielle',
version = '0.1',
author
= "Pierre Navaro",
description = """ Cython example of exponential function """,
ext_modules = [module_cython],
cmdclass = {'build_ext':build_ext}
)
avec la commande :
$ python setup.py build_ext --inplace
Puis tester votre module Cython avec :
print "Cython..."
t = Timer("exp_cython.exp_c(1.,50)", "import exp_cython")
print "1,000,000 calls : %s " % t.timeit()
9
6.6
f2py
Créer le module exp_f2py dans le fichier d’interface f2py nommé exp_f2py.pyf. Créer
la fonction C modifiée dans le fichier exp_f2py.c :
void exp_c(double x, int terms, double * res)
{
double power;
double fact;
int i;
res[0] = 0.;
power = 1.;
fact = 1.;
for (i=0;i<terms;i++)
{
res[0] += power/fact;
power *= x;
fact *= i+1;
}
}
Compiler votre module avec la commande :
$ f2py -m exp_f2py -c exp_f2py.c exp_f2py.pyf --opt=-O3
Tester votre module :
print "F2PY..."
t = Timer("exp_f2py.exp_c(1.,50)", "import exp_f2py")
print "1,000,000 calls : %s " % t.timeit()
6.7
Performances
Comparer tous les résultats avec la fonction exponentielle du package math.
7
Corrigés
1.1 https://perso.univ-rennes1.fr/pierre.navaro/python/exercices/ex1.py
1.2 https://perso.univ-rennes1.fr/pierre.navaro/python/exercices/ex2.py
1.3 https://perso.univ-rennes1.fr/pierre.navaro/python/exercices/ex3.py
2.1 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex1.py
2.1 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex2.py
2.1 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex3.py
2.1 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex4.py
2.1 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex5.py
2.2 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex6_correct.
py
2.2 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex7_correct.
py
2.3 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex8.py
10
2.3 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex9.py
2.4 https://perso.univ-rennes1.fr/pierre.navaro/python/numpy/ex10.py
3.2 https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex2.py
3.3 https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex3.py
3.4 https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex5.py
3.5 https://perso.univ-rennes1.fr/pierre.navaro/python/matplotlib/ex7.py
4.1 https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/ex2.py
4.3 https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/mypackage/assemble.
py 1
4.4 https://perso.univ-rennes1.fr/pierre.navaro/python/scipy/mypackage/laplace2d.
py
5.2 https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/dgemm.pyf
5.4 https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/lap2d_module.
f90
5.4 https://perso.univ-rennes1.fr/pierre.navaro/python/f2py/laplacian2d_
2.py
6.1 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exp_py.py
6.4 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exp_c.i
6.5 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exp_cython.pyx
6.5 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/setup.py
6.6 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exp_f2py.pyf
6.7 https://perso.univ-rennes1.fr/pierre.navaro/python/swig/exponentielle.
py
1. Sylvain Faure Cours Scipy, ANGD Python en Calcul scientifique
11
Téléchargement