## 1. Project Overview & Quickstart (rossant/CONTRIBUTING)

# CONTRIBUTING

Open-source repository rossant/CONTRIBUTING

### Repository Details
- **Repository:** [rossant/CONTRIBUTING](https://github.com/rossant/CONTRIBUTING)
- **Primary Language:** Code

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (rossant/website)

## File: README.md

To build with:

* pelican `master`
* `pelican-plugins`, `rossant` fork, `ipynb` branch (to add IPython notebook reader that converts a notebook to Markdown, by keeping or not the input code with `keep_input` metadata field)
* need `pelican_plugin-render_math`
* `Python-Markdown`, `rossant` fork, `codehilite-lang-param` branch (to set Python as default language for code highliting)

---

## File: content/pages/books.md

Title: Books

I've written two books on Python for data science.


<a name="cookbook"></a>
## IPython Cookbook
september 2014


	
		[](http://ipython-books.github.io/cookbook/)
	

	
		<h3>[IPython Interactive Computing and Visualization Cookbook](http://ipython-books.github.io/cookbook/)</h3>
		Packt Publishing (520 pages, 30$)

		
			This advanced-level book covers a wide range of methods for data science with Python:
		

		
			<li>Advanced interactive computing in the IPython notebook</li>
			<li>High-performance computing with Python</li>
			<li>Statistics, machine learning, data mining</li>
			<li>Signal processing and mathematical modeling</li>
		
	



<a name="minibook"></a>
## IPython Minibook, second edition
october 2015


    
        [](http://ipython-books.github.io/minibook/)
    

    
        <h3>[Learning IPython for Interactive Computing and Data Visualization, second edition](http://ipython-books.github.io/minibook/)</h3>
        Packt Publishing (175 pages, 25$)

        
            This book is a beginner-level introduction to Python for data analysis:
        

        
            <li>Interactive Python with IPython</li>
            <li>Data analysis with pandas</li>
            <li>Numerical computing with NumPy/SciPy</li>
            <li>Data visualization with matplotlib</li>

---

## File: content/pages/projects.md

Title: Projects

## Platform for large-scale electrophysiological data analysis

Next-generation electrophysiological recording devices require scalable data analysis platforms. I'm leading the development of a new [Python-based platform](http://klusta-team.github.io/) that will let scientists analyze their terabytes of data remotely and effectively in the Web browser (thanks to the [IPython notebook](http://ipython.org/notebook.html)).

I'm focusing on raw data visualization and extraction of spike trains from raw extracellular recordings (spike sorting).


## High-performance big data visualization

I've developed a [technology for high-performance interactive visualization of big data]({filename}/pdfs/RossantHardware2013.pdf) based on optimal use of the graphics processing unit (GPU). It is based on modern OpenGL (GLSL shaders) and it uses techniques originally created for 3D video games.

I'm now a core developer of [Vispy](http://vispy.org/), a collaborative project in Python that aims at bringing to scientists high-level, user-friendly visualization facilities based on this technology.

I'm also interested in bringing Vispy to the browser. This will let scientists visualize huge volumes of data remotely thanks to [WebGL](http://en.wikipedia.org/wiki/WebGL), a browser-based implementation of OpenGL.


## Python for data science

I've written [two books on Python for data science and interactive computing]({filename}/pages/books.md).

The first book is a beginner-level introduction to Python for data analysis and numerical computing.

The second book is an advanced-level guide to data science with Python, covering technical aspects of interactive and high-performance computing as well as applied mathematics topics such as statistics, machine learning, signal processing, computer vision, numerical optimization, network data analysis, and mathematical modeling for data science. The book contains more than 100 hands-on recipes applied on real-world examples.


## Open data

I analyze public datasets with Python and I make data visualizations.

* [Map of all road accidents in France in 2012](/opendata-interior-hackathon/), realized with [Rue89](http://rue89.nouvelobs.com/2014/06/25/carte-presque-tous-les-accidents-route-2012-253113) journalists during an [Open Data Hackathon organized by the French Minister of the Interior](http://fr.okfn.org/2014/08/09/retour-sur-le-premier-hackathon-sur-les-donnees-du-ministere-de-linterieur/). I gathered several data sources with IPython and pandas to create the final dataset of all accidents.
* [Vélib' in Paris](/velib-open-data/)
* First names of students taking their high-school diplomas (in French, based on an [original study by Baptiste Coulmont](http://coulmont.com/blog/2012/07/08/prenoms-mentions-bac-2012/)): [post 1](/prenoms-et-reussite-au-bac/) and [post 2](/frequence-des-prenoms-des-candidats-au-bac-2012/)

---

## File: content/pages/resume.md

Title: Resume

I am a former student of [&Eacute;cole Normale Supérieure](http://www.ens.fr), where I studied mathematics and computer science. I also have a PhD in neuroinformatics.

Here is a resume of my current and past professional activities.

## Professional experience

### Analysis of large-scale electrophysiological data

2012&ndash;present (postdoc)

* [Cortical Processing Laboratory](http://www.ucl.ac.uk/cortexlab) ([Kenneth D. Harris](https://iris.ucl.ac.uk/iris/browse/profile?upi=KDHAR02))
* [University College London](http://www.ucl.ac.uk/), UK

I'm developing algorithms and software for analyzing large volumes of electrophysiological data (high-density multielectrode arrays).


### Correlations in neural coding

2009&ndash;2012 (PhD)

* [Cognitive Studies Department](http://www.cognition.ens.fr/) ([Romain Brette](http://romainbrette.fr/))
* [&Eacute;cole Normale Supérieure](http://www.ens.fr/), France

I've developed programs for analyzing intracellular recordings with the help of spiking neuron models. I've also demonstrated theoretically and experimentally a key role for fast temporal correlations in neural coding. [My dissertation is available for download here (PDF, 14MB)]({filename}/pdfs/RossantPhD.pdf).


### Statistical data analysis of retinal spiking data

2008 (six-months research internship)

* [Molecular Biology Department](http://molbio.princeton.edu/) ([Michael Berry](http://molbio.princeton.edu/faculty/molbio-faculty/95-berry))
* [Princeton University](http://www.princeton.edu/main/), USA

I've developed a statistical framework for analyzing and modeling the multineuronal spiking activity of retinal ganglion cells recorded with high-density multielectrode arrays (joint work with Kolia Sadeghi). [My dissertation is available for download here (PDF, 2MB)]({filename}/pdfs/RossantMasterThesis.pdf).


### Data analysis of human locomotor trajectories

2007 (two-months research internship)

* [Laboratory of Action and Perception Physiology](http://www.lppa.college-de-france.fr/) ([Alain Berthoz](http://www.lppa.college-de-france.fr/equipes/people/Berthoz/))
* [Collège de France](http://www.college-de-france.fr/site/college/index.htm), France

I've conducted data analysis and modeling investigations of locomotor trajectories recorded with motion-capture cameras.


## Publications and conferences

### International peer-reviewed scientific journals

  * **Rossant C**, Harris KD (2013). [Hardware-accelerated interactive data visualization for neuroscience in Python]({filename}/pdfs/RossantHardware2013.pdf). Frontiers in Neuroinformatics, 7(36); doi:10.3389/fninf.2013.00036
  * **Rossant C**, Fontaine B, Goodman DF (2013). [Playdoh: a lightweight Python library for distributed computing and optimisation]({filename}/pdfs/RossantPlaydoh2013.pdf). Journal of Computational Science, 4(5): 352–359; doi:10.1016/j.jocs.2011.06.002
  * **Rossant C**, Fontaine B, Magnusson AK, Brette R (2012). [A calibration-free electrode compensation method]({filename}/pdfs/RossantCalibration2012.pdf). Journal of Neurophysiology, 108(9): 2629-2639; doi: 10.1152/jn.01122.2011
  * **Rossant C**, Leijon S, Magnusson AK, Brette R (2011). [Sensitivity of noisy neurons to coincident inputs]({filename}/pdfs/RossantSensitivity2011.pdf). Journal of Neuroscience, 31(47): 17193-17206; doi: 10.1523/JNEUROSCI.2482-11.2011
  * **Rossant C**, Goodman DF, Fontaine B, Platkiewicz J, Magnusson A, Brette B (2011). [Fitting neuron models to spike trains]({filename}/pdfs/RossantFitting2011.pdf). Frontiers in Neuroscience, 5:9. doi:10.3389/fnins.2011.00009
  * **Rossant C**, Goodman D, Platkiewicz J, Brette R (2010). [Automatic fitting of spiking neuron models to electrophysiological recordings]({filename}/pdfs/RossantAutomatic2010.pdf). Frontiers in Neuroinformatics, 4:2. doi:10.3389/neuro.11.002.2010







### Magazines

  * **Rossant C** (2015, in prep). Visualization of large datasets with VisPy. French Linux Magazine, upcoming Big Data special issue, 2015
  * **Rossant C** (2015, in prep). Introduction to scikit-learn. French Linux Magazine, upcoming Big Data special issue, 2015
  * **Rossant C** (2014). [VisPy: visualisation interactive haute performance](http://boutique.ed-diamond.com/gnulinux-magazine-hors-series/597-gnulinux-magazine-hs-73.html). French Linux Magazine, Scientific Python special issue, summer 2014


### Books

  * **Rossant C** and Klein A (2015, in press). WebGL Insights. CRC Press (chapter of a community book)
  * **Rossant C** (2015, in prep). Learning IPython for Interactive Computing and Data Visualization, second edition. Packt Publishing, ISBN 9781783986989
  * **Rossant C** (2014). [IPython Interactive Computing and Visualization Cookbook](http://www.packtpub.com/ipython-interactive-computing-and-visualization-cookbook/book). Packt Publishing, 520 pages, ISBN 9781783284818
  * **Rossant C** (2013). [Learning IPython for Interactive Computing and Data Visualization](http://www.packtpub.com/learning-ipython-for-interactive-computing-and-data-visualization/book). Packt Publishing, 138 pages, ISBN 9781782169932


### Conferences

* Kadir S, **Rossant C**, Goodman D, Schulman J, Hunter M, Belluscio M, Buzsaki G, Harris D (2014). Spike sorting for large dense arrays. Society for Neuroscience Annual Meeting, Washington, USA (poster)
* Klein A, Rougier N, **Rossant C**, Larson E, Campagnola L (2014). [Introducing VisPy's high level modules: easy yet powerful visualization for everyone](https://www.euroscipy.org/2014/schedule/presentation/7/). EuroSciPy, Cambridge, UK (talk by Klein A)
* **Rossant C**, Harris K (2013). Spike sorting for large dense electrode arrays: User interface software. Society for Neuroscience Annual Meeting, San Diego, USA (poster)
* **Rossant C** (2013). Spike-based computation in cortical networks: theory and data, Mathematical Neuroscience Laboratory, CIRB, Collège de France, Paris
* Campagnola L, Klein A, **Rossant C**, Rougier N (2013). A Modern and Interactive Visualization Framework, EuroSciPy, Brussels, Belgium (talk by Rougier N)
* **Rossant C**, Harris K (2013). High-performance interactive data visualization in Python. EuroSciPy, Brussels, Belgium (poster)
* **Rossant C**, Harris K (2013). Spike sorting for large dense electrode arrays: User interface software. Organization for Computational Neuroscience Meeting, Paris (poster)
* **Rossant C**, Harris K (2013). Spike sorting for large dense electrode arrays: User interface software. UCL Neuroscience Symposium, London (poster)
* **Rossant C** (2013). Semi-automatic algorithms for manual spike sorting, Cortical Processing Laboratory Seminar, UCL, London
* **Rossant C**, Harris K (2013). Spike sorting for large dense electrode arrays: User interface software. British Neuroscience Association's biennial meeting, London (poster)
* **Rossant C** (2011). Coincidence detection in noisy neurons, Laboratory of Computational Neuroscience Seminar, EPFL, Lausanne, Switzerland
* **Rossant C**, Leijon S, Magnusson AK, Brette R (2011). Sensitivity of noisy neurons to coincident inputs. Workshop on Mean-field methods and multiscale analysis of neuronal populations, CIRM, Marseille, France (poster)
* Brette R, **Rossant C**, Benichoux V (2011). What's new in Brian? Python in Neuroscience Euroscipy Workshop, Paris (talk)
* **Rossant C**, Brette R (2010). Coincidence detection in noisy neurons. Society for Neuroscience Annual Meeting, San Diego, USA (poster)
* **Rossant C**, Brette R (2010). Coincidence detection in noisy neurons. NeuroComp, Lyon, France (poster)
* **Rossant C**, Fontaine B, Goodman DF (2010). Playdoh: a lightweight Python library for distributed computing and optimisation. Euroscipy 2010, Paris (talk)
* **Rossant C**, Brette R (2010). Coincidence detection in active neurons. Cosyne, Salt Lake City, USA (poster)


### Workshops and tutorials

* **Rossant C**, Rougier N, Klein A, Campagnola L, Larson E, Zaid I, Hunter M (2015). VisPy sprint, Collège de France, Paris (organization and participation to the sprint)
* **Rossant C**, Harris K (2014). File formats for large-scale electrophysiology. Janelia Workshop, Janelia Farm Research Campus, Ashburn, USA (invited talk)
* **Rossant C** (2014). [The new interactive features of the IPython 2 notebook](https://www.euroscipy.org/2014/schedule/presentation/60/), EuroSciPy, Cambridge, UK (advanced tutorial)
* Rougier N, Klein A, **Rossant C** (2014). VisPy sprint, EuroSciPy, Cambridge, UK (sprint)
* **Rossant C**, Rougier N (2014). [Scientific Data Visualization](http://reseau-loops.github.io/journee_2014_06.html), LoOPS network meeting, Orsay University. Presentation and tutorials on HDF5 and VisPy
* **Rossant C**, Klein A, Campagnola L, Rougier N (2014). Organization of the VisPy code camp at the European Synchrotron Radiation Facility (ESRF) in Grenoble
* Rougier N, Klein A, **Rossant C** (2013). Python visualization, EuroSciPy, Brussels, Belgium (sprint)
* Brette R, Stimberg M, Benichoux V, **Rossant C**, Goodman D, Fontaine B (2013). Advanced modelling of spiking neural networks with Brian. Organization for Computational Neuroscience Meeting, Paris (tutorial)
* **Rossant C**, Harris K (2013). Next-generation software for spike sorting with large multi-electrode probes. Janelia Spike Sorting Workshop, Janelia Farm Research Campus, Ashburn, USA (invited talk)


## Grants and awards

* Research grant (2014-2015). Cooperation between Paris-Sciences-Lettres (PSL) and University College London.


## Education and diplomas

* 2012: **PhD in computational neuroscience** at the ENS and UPMC with highest honors
* 2008: **Master's Degree in computer science** (MPRI) at the ENS with highest honors
* 2005: **Bachelor's Degree in mathematics** ([FIMFA](https://www.math.ens.fr/enseignement/Presentation,7.html)) at the ENS with highest honors
* 2005: Entry to the **&Eacute;cole Normale Supérieure** (ENS) through competitive examinations in maths and physics
* 2002: Preparatory classes (MPSI/MP*) at Lycée Masséna, Nice
* 2002: High school diploma (A-level equivalent) with highest honors


## Teaching

* 2009-2012: **Teacher assistant** in mathematics and computer science at ENS and UPMC (Bachelor and Master levels): probability theory, measure theory, statistics, calculus, real analysis, dynamical systems, signal processing, scientific Python

* 2009-: Private lessons in mathematics to students in high school and preparatory classes

* 2008-2009: Voluntary teaching to high school students at [TALENS](http://pesu.ens.fr/talens/) association


## Technical skills

* Applied mathematics: statistics, data mining, machine learning, signal processing, image processing and computer vision, mathematical optimization, dynamical systems, graph theory, high-dimensional data analysis, computational geometry
* Scientific Python, MATLAB, data visualization
* Programming on graphics cards: CUDA, OpenCL
* Computer graphics: OpenGL, DirectX, ray tracing, video game development, Photoshop, Illustrator
* Website development: HTML5, CSS3, JavaScript, Backbone, D3js, PHP/MySQL
* Mobile and windows applications: C#, .NET, Windows Phone, Qt
* Other languages: C, C++, assembly, Perl, Java

---

## File: content/2012-07-02-python-ide-windows.md

Title: Build a Python IDE for Windows with Notepad++ and IPython
Tags: python

I've been looking for a good and free Python IDE for Windows for a long time. I first used
[Eclipse](http://www.eclipse.org/) and [Pydev](http://pydev.org/), but
Eclipse is a bit of a *"usine à gaz"*. I tried
[Spyder](http://code.google.com/p/spyderlib/) but it crashed too often
and it was not flexible enough. I ended up using
[Notepad++](http://notepad-plus-plus.org/), a really fast and powerful
text editor, with the great command-line interpreter
[IPython](http://ipython.org/). Notepad++ is extremely light to use,
opens within a second, and contains most important features a Python
developer wants (syntax highlighting, automatic indentation, code
folding...). However, it does not include a native way for running
Python scripts. On the other hand, IPython is a widely used and
extremely powerful Python interpreter that is well adapted for
scientific computing. It allows to run scripts in a command-line
interface, and offers the possibility to continue an interactive session
afterwards. It also includes a debugger and many more features.



Unfortunately, using both Notepad++ and IPython in a convenient way
during an interactive session, where one edits a script and runs it many
times, is not straightforward. One can simply open both programs, with
IPython opened in the script directory, and call the magic *%run
script.py* command repeatedly. However, when calling *%run* several
times, the Python script is correctly reloaded every time, but not the
imported modules that could also have been edited in Notepad++. In other
words, if one runs a script which depends on different modules, and
edits one such module, those modifications won't be effective at the
next *%run* command. One has to import and reload that specific module,
which can be tiresome when editing a lot of different modules. There
appears to be no way of resetting the whole IPython environment and
reloading all modules. So typically one has to close and open again
IPython in the right working directory. This is cumbersome since every
edition-evaluation loop requires to close the IPython interpreter, open
it again, put the window at a convenient place on the screen, go in the
right directory, and run the script. Over and over again, even when
changing just one line of code in an imported script.

Those little issues might seem unimportant, but they can really hurt
productivity and prevent the user from focusing on its core work.
Therefore I've been looking for a way of automating this interactive
edition-evaluation loop with Notepad++ and IPython. The goal is to let
the user press a single keyboard button (e.g. F6) in a Python script
opened in Notepad++ in order to execute it in IPython. One should have
also a simple way of reloading all modules if needed. Here is what I
came up with. This method may certainly be improved, and it could even
be adapted to other OS than Windows.

This method works with Python 2.7, IPython 0.13 and Notepad++ 6.1.3 (it
will probably work with other versions, but it may require small
modifications).

First, create a custom IPython script that will define two new magic
commands in IPython called *%cdrun* and *%cdrunkill*. Both open a new
IPython interpreter, set a specific working directory, and run a Python
script. The second command also kills any existing IPython interpreter
(corresponding to a hard restart of IPython). This script will be loaded
at every IPython launch, so it should be placed here:

    :::text
    C:\Users\\.ipython\profile_default\startup\cdrun.py

This file contains the following code.

    :::python
    import os
    from subprocess import Popen, PIPE

    ip = get_ipython()

    def kill_python():
        # kill all other python processes
        pid = str(os.getpid())
        cmd = ['tasklist', "/FO", "LIST", "/FI", "IMAGENAME eq python.exe"]
        r = Popen(cmd, stdout=PIPE).communicate()[0]
        r = r.split("\n")
        ps = []
        for line in r:
            if line[:3] == 'PID':
                ps.append(line[4:].strip())
        if pid in ps:
            ps.remove(pid)
        n = len(ps)
        if n == 0:
            return
        args = " ".join(["/pid %s" % p for p in ps])
        cmd = "taskkill /F %s" % args
        os.system(cmd)
        return n

    def cdrun(self, arg):
        h, t = os.path.split(arg)
        ip.magic("cd %s" % h)
        ip.magic("run %s" % t)

    def cdrunkill(self, arg):
        kill_python()
        h, t = os.path.split(arg)
        ip.magic("cd %s" % h)
        ip.magic("run %s" % t)

    ip.define_magic('cdrun', cdrun)
    ip.define_magic('cdrunkill', cdrunkill)

The *kill\_python* function kills all Python processes except the
current one. Hence this script allows to automatically close a previous
IPython interpreter and open a new one, resolving the module reloading
issue. If you want to open a new IPython interpreter without killing all
Python processes (for example, with a multicore computer, launching
several scripts in different IPython interpreters can make them run in
parallel on several CPUs), you can use the first command *cdrun*.

Next, you can specify the screen location and the size of the Ipython
window. It is very convenient because it allows you to put the
Notepad++, say, on the left of the screen, and the IPython interpreter
on the right, so that you don't have to manually move the IPython window
every time you launch a new interpreter (otherwise Windows tends to put
it at random locations). To do this, [edit the window properties of the
IPython prompt](http://commandwindows.com/configure.htm) (see method on
this website).

Third, define a new macro in Notepad++, by editing or creating the
following file:

    :::bash
    # in C:\Users\\AppData\Roaming\Notepad++\shortcuts.xml
    ipython -i -c "%cdrun $(FULL_CURRENT_PATH)"  
    ipython -i -c "%cdrunkill $(FULL_CURRENT_PATH)"

The buttons \#117 and \#118 correspond to F6 and F7 here. If other
commands exist, just add the *\<Command\>* lines in the
*\* section. If those shortcuts don't work, it may
be because they are already assigned to other commands: go in Settings,
then Shortcuts, and remove them.

Also, do not edit this XML file with Notepad++, because your
modifications may be discarded when you close Notepad++. Instead, ensure
that Notepad++ is closed, edit the file with Notepad, and reopen
Notepad++.

Now, when you open a Python script in Notepad++, you can press F6. It
will launch an IPython window and execute the script. At the end of the
execution, you can interact in the IPython interpreter. If you need to
execute the script again, just use the following command:

    :::python
    %run script.py

This will reload *script.py*, but not other modules. If you need to
reload everything, press F7 in Notepad++: it will close the IPython
window and open a new one, at the same location on the screen. This
gives you the illusion of a very light and basic Python IDE, and allows
you to benefit from both the great editing features of Notepad++ and the
powerful IPython interpreter at the same time.

**Note**: you can automate the process of re-evaluating the script in
IPython. Here, you need to: save the script in Notepad++, set the focus
to IPython (with the mouse or with ALT+TAB), and type again the *%run*
command (or selecting it in the command history). With the very powerful
tool [AutoHotkey](http://www.autohotkey.com/), you can create a simple
script for automating these keystrokes. Create a text file named
"ipython\_update.ahk" somewhere and put the following code:

    :::ahk
    SetTitleMatchMode, 2
    IfWinExist Notepad`+`+
    {
        WinActivate
        Send ^s
        SetTitleMatchMode, 1
        IfWinExist ipython
        {
            WinActivate
            Send `%run %1%`r
        }
    }

Now, in Notepad++, create a new command for launching this script with
the current file as parameter:

    :::bash
    autohotkey [YOURPATH]\ipython_update.ahk $(FILE_NAME)

Ensure that the autohotkey.exe binary is in the Windows Path. Now,
pressing F8 in Notepad++ will automatically set the focus to IPython and
run your script.

**Note for Linux users**: Here is a Python function for killing all
Python processes except the current one on Linux that might be useful.

    :::python
    def kill_python():
        """
        Linux version (not very well tested, might need some tweaking)
        """
        pid = str(os.getpid())
        cmd = "ps -ef | grep python | awk '{print $2}'"
        r = commands.getoutput(cmd)
        r = r.split('\n')
        if pid in r:
            r.remove(pid)
        n = len(r)
        r = ' '.join(r)
        cmd = 'kill %s' % r
        os.system(cmd)
        return n

---

## File: content/2012-07-04-introduction-to-bayesian-thinking.md

Title: Introduction to Bayesian thinking
Tags: maths

An updated version of this post can be found in the [IPython Cookbook](http://ipython-books.github.io/). It will also be available here soon.

---

## File: content/2012-07-12-prenoms-et-reussite-au-bac.md

Title: Prénoms et réussite au bac
Tags: opendata

Le sociologue Baptiste Coulmont, auteur de 
*[Sociologie des prénoms](http://coulmont.com/livres/prenoms/)*, s'est
intéressé aux corrélations entre le prénom des candidats au baccalauréat
2012 et leur réussite à cet examen ([voir ici pour l'étude originale sur
le blog de
l'auteur](http://coulmont.com/blog/2012/07/08/prenoms-mentions-bac-2012/)).
Ce travail a été [largement relayé par les
médias](http://www.lepoint.fr/societe/les-prenoms-qui-reussissent-au-bac-10-07-2012-1483876_23.php),
car les résultats sont particulièrement intéressants. Il s'avère que
certains prénoms réussissent mieux que d'autres: les Madeleine et autres
Côme réussissent bien mieux (plus de 25% de mentions TB chez ces
candidats) que les Youssef ou Nabil (aucune mention TB cette année). Ce
n'est probablement pas le prénom en lui-même qui influe sur le résultat,
mais plutôt le fait que le prénom est souvent le reflet de certains
critères sociologiques (classe sociale, origine géographique, profession
des parents...). Ce sont ces derniers critères qui ont une influence
certaine sur les résultats scolaires, démontrant des inégalités
profondes dans le système éducatif actuel.



**EDIT**: [maintenant, vous pouvez connaître les résultats des candidats
portant votre prénom!](http://coulmont.com/bac/)

J'ai voulu effectuer quelques analyses complémentaires sur ces mêmes
données, en m'intéressant plus aux aspects mathématiques que
sociologiques. Il peut s'agir d'un exemple intéressant dans
l'enseignement d'un cours de probabilité et statistiques, illustrant
notamment les notions de
[conditionnement](http://fr.wikipedia.org/wiki/Probabilit%C3%A9_conditionnelle),
d'[espérance
conditionnelle](http://fr.wikipedia.org/wiki/Esp%C3%A9rance_conditionnelle),
de [raisonnement
bayésien](http://fr.wikipedia.org/wiki/Inf%C3%A9rence_bay%C3%A9sienne),
ou de [divergence de
Kullback-Leibler](http://fr.wikipedia.org/wiki/Divergence_de_Kullback-Leibler).

Résultat moyen en fonction du prénom
------------------------------------

Nous nous intéressons au **profil de résultats**: il s'agit d'une courbe
donnant la proportion de candidats pour chaque résultat possible: oral
(O), passable (P), mention assez bien (AB), mention bien (B), mention
très bien (TB). Cela s'appelle aussi une distribution de probabilité sur
l'ensemble des résultats possibles. Voici le profil moyen, pour tous les
candidats et indépendamment du prénom. **Il y a environ 17% de candidats
devant passer l'oral, 35% de P, 27% de AB, 14% de B, 7% de TB**.
Rappelons que ces chiffres comportent deux biais: il ne s'agit que des
candidats ayant obtenu l'examen après le premier écrit, ou ayant obtenu
la possibilité de passer l'oral. Les candidats ayant échoué après le
premier écrit ne sont pas inclus dans les données. Le deuxième biais
concerne le fait que seuls les candidats ayant accepté de diffuser
publiquement leurs résultats sont inclus.



Maintenant, nous nous intéressants à l'influence du prénom sur le
résultat au bac. Nous allons utiliser deux approches mathématiques: la
première utilise l'**espérance conditionnelle**, la seconde utilise la
**divergence de Kullback-Leibler**. Dans les deux cas, l'idée est de
comparer le profil moyen avec le profil pour chaque prénom. Cela revient
à étudier la distribution de probabilité conditionnelle à la donnée du
prénom. En d'autres termes, si un candidat pris au hasard a 7% d'avoir
eu mention TB, le fait de savoir qu'il s'appelle Côme, Nicolas, ou
Youssef change-t-il cette probabilité? Cette question correspond au
principe mathématique de **conditionnement**. Du point de vue de
l'espérance conditionnelle, on peut se demander, si la moyenne générale
au bac est de 12 chez tous les candidats, combien de points en plus on
peut attendre chez un candidat en connaissant son prénom? D'un point de
vue bayésien, on peut aussi voir la question ainsi: connaissant le
profil de résultat moyen (prior), le fait de connaître le prénom
change-t-il le profil de résultat (posterior)?

Moyenne au bac
--------------

Dans cette première approche, nous nous intéressons à la moyenne des
candidats, sachant ou non leurs prénoms. Mathématiquement, il s'agit
respectivement de l'espérance de la distribution moyenne du résultat, et
de l'*espérance conditionnelle* de cette distribution *sachant* le
prénom du candidat. Pour cela, nous assignons d'abord une note moyenne à
chaque mention: 9 pour O, 11 pour P, 13 pour AB, 15 pour B, 17 pour TB.
Il ne s'agit bien sûr que d'une approximation, puisque nous n'avons
accès qu'à la mention et pas à la note moyenne de chaque candidat. Chez
tous les candidats (ayant réussi ou devant passer l'oral, donc), la
moyenne globale est de 12.2.

Nous pouvons ensuite, pour chaque prénom, calculer l'écart, par rapport
à cette moyenne, de la moyenne des candidats portant ce prénom (ou
espérance conditionnelle). Nous trouvons que cet écart varie entre -2.1
(Nahida) et +2.1 (Gaëtane), soit une bonne mention d'écart. **Autrement
dit, une Nahida a en moyenne *une mention en-dessous* de la mention
moyenne des candidats, comparé à *une mention au-dessus* pour une
Gaëtane**. Voici le profil de résultat des six prénoms les plus
en-dessous de la moyenne:



Voici les résultats complets pour les 30 prénoms les plus en-dessous,
avec l'écart à la moyenne.

    :::text
    Nahida       -2,07
    Alyson       -1,97
    Imad         -1,91
    Nadir        -1,80
    Mariama      -1,75
    Bilel        -1,65
    Fatma        -1,63
    Abdelkader   -1,60
    Manuella     -1,59
    Aziza        -1,57
    Yassin       -1,57
    Mounir       -1,57
    Moussa       -1,56
    Siham        -1,55
    Patrice      -1,53
    Kamel        -1,53
    Giovanni     -1,53
    Dalila       -1,47
    Abdel        -1,45
    Erwin        -1,42
    Nordine      -1,41
    Khalid       -1,40
    Latifa       -1,40
    Youssef      -1,38
    Sofian       -1,38
    Souad        -1,37
    Soumia       -1,37
    Bilal        -1,36
    Alysson      -1,36
    Lamia        -1,35

Du côté des prénoms avec l'écart le plus au-dessus de la moyenne, voici
les profils de résultats.



    :::text
    Gaetane        2,13
    Madeleine      1,94
    Ariane         1,82
    Come           1,76
    Marguerite     1,73
    Isaure         1,71
    Mahaut         1,61
    Marie-Anne     1,58
    Hannah         1,51
    Melisande      1,46
    Viviane        1,45
    Quitterie      1,43
    Marie-Astrid   1,43
    Guillemette    1,38
    Anouk          1,35
    Irene          1,34
    Blaise         1,33
    Arielle        1,33
    Solange        1,33
    Leon           1,31
    Domitille      1,29
    Celeste        1,23
    Noemi          1,23
    Cleo           1,23
    Hortense       1,22
    Baudouin       1,19
    Jack           1,19
    Iris           1,17
    Jolan          1,17
    Gaspard        1,16

Destin des prénoms
------------------

Avec la seconde méthode, nous nous intéressons à la quantité
d'information obtenue avec la connaissance du prénom. Autrement dit,
posons-nous d'abord la question suivante:

-   **Quel résultat attendre d'un candidat pris au hasard?**
-   *Réponse*: voir le profil de résultat moyen au début de cet article,
    supposé connu a priori (7% de mention TB, 14% de mentions B, etc.).

Ensuite:

-   Quel résultat attendre d'un candidat pris au hasard, *si l'on nous
    donne son prénom*? Plus précisément, **à quel point notre attente du
    résultat est-elle modifiée par la connaissance de son prénom**?
-   *Réponse*: la **divergence de Kullback-Leibler** entre la
    distribution moyenne, et la distribution conditionnée au prénom,
    donne une réponse quantitative à cette question.

Cette divergence constitue une sorte de métrique entre deux
distributions. Une divergence quasi-nulle signifie que les distributions
sont quasi-identiques, donc que notre attente du résultat n'est pas
modifiée par la connaissance du prénom. A l'inverse, une divergence plus
élevée signifie que la connaissance du prénom change de manière
importante le résultat que l'on peut attendre du candidat ([voir ici
pour des
détails](http://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence#KL_divergence_and_Bayesian_updating)).
Les graphiques ci-dessous illustrent cela.

Voici d'abord les six prénoms associés à la divergence la plus élevée.
Nous reconnaissons les prénoms obtenus plus haut, sauf que les prénoms
réussissant le mieux sont mélangés avec ceux réussissant le moins. En
effet, cette mesure signifie à quel point les profils de résultats sont
différents de la moyenne, mais pas la direction de cette différence, qui
peut être meilleure (plus de bonnes mentions) ou moins bonne (plus de
mauvais résultats).



Voici les 30 prénoms associés à la divergence la plus élevée.

    :::text
    Nahida
    Alyson
    Imad
    Nadir
    Alysson
    Gaetane
    Tina
    Mariama
    Patrice
    Madeleine
    Aziza
    Come
    Fatih
    Bilel
    Manuella
    Moussa
    Fatma
    Giovanni
    Abdelkader
    Cleo
    Elia
    Erwin
    Isaure
    Abdel
    Siham
    Zelie
    Yassin
    Mounir
    Juliane
    Leon

Maintenant, nous pouvons aussi nous intéresser aux **prénoms avec la
divergence la plus faible**, autrement dit les prénoms les plus
représentatifs de l'ensemble des candidats. Ces prénoms sont
probablement répartis de manière uniforme parmi tous les candidats, sans
être associés, par exemple, à une classe sociale particulière qui aurait
des résultats très différents de la moyenne. Ainsi, un Valentin ou une
Emilie a un profil de résultat tout à fait comparable à la moyenne
globale.



    :::text
    Valentin
    Emilie
    Nicolas
    Alexandra
    Clement
    Laura
    Thomas
    Arnaud
    Remy
    Alexandre
    Helene
    Hugo
    Mario
    Bastien
    Sebastien
    Estelle
    Xavier
    Romain
    Quentin
    Eva
    Guillaume
    Rayan
    Vincent
    Adrien
    Sabine
    Ines
    Lucas
    Sarah
    Floriane
    Virgile

En conclusion, nous avons donné des méthodes pour trouver les prénoms
qui influent le plus (positivement ou négativement) sur le résultat au
bac, et à l'inverse pour trouver ceux qui ont le moins d'impact sur le
résultat et qui sont le plus proches possible des résultats globaux. Il
y a probablement beaucoup d'autres choses à analyser dans ces données.

Méthodes
--------

*Données.* Les données concernent les résultats de 346851 candidats,
toutes séries confondues (générales et technologiques), qui ont au moins
eu l'oral et qui ont accepté de rendre disponible publiquement leur
résultat. Tous ces candidats portent 18473 prénoms différents. Pour les
analyses, nous n'avons considéré que les prénoms portés par au moins 20
candidats, soit 1211 prénoms différents représentant 310145 candidats.

*Modélisation*. L'ensemble des candidats est noté
$\Omega$, l'ensemble des 1211 prénoms est noté
$E$, l'ensemble des résultats possibles est noté
$F$. L'ensemble $\Omega$ est muni de la tribu
discrète et de la mesure de probabilité uniforme. Les variables
aléatoires $X(\omega)$ et $Y(\omega)$ sont
des variables aléatoires à valeurs dans $E$ et
$F$, respectivement, et donnant le prénom et le résultat de
chaque candidat. Voici les formules utilisées.

-   La probabilité de $y$ est:
    

    $$
    p[y]=\frac{\textrm{card}\left\{\omega \in
    \Omega \mid Y(\omega)=y\right\}}{\textrm{card}(\Omega)}  
    $$

-   La probabilité conditionnelle de $y$ sachant
    $x$ est:
    
    $$ 
    p[y\mid x] = \frac{\textrm{card}\left\{\omega
    \in \Omega \mid X(\omega)=x,
    Y(\omega)=y\right\}}{\textrm{card}\left\{\omega \in \Omega
    \mid X(\omega)=x\right\}}  
    $$

-   L'espérance de $y$ est:
    
    $$
    E[y]=\sum_{y \in F} y \times p[y]  
    $$


-   L'espérance conditionnelle de $y$ sachant
    $x$ est:
    
    $$
    E[y \mid x]=\sum_{y \in F} y \times p[y \mid
    x]  
    $$

-   La divergence de Kullback-Leibler entre la distribution
    $p[y]$ et la distribution conditionnelle
    $p[y\mid x]$ est:
    
    $$ 
    D(x)=\sum_{y \in F} p[y \mid x] \times
    \log\left(\frac{p[y \mid x]}{p[y]}\right)  
    $$

---

## File: content/2012-07-14-frequence-des-prenoms-des-candidats-au-bac-2012.md

Title: Fréquence des prénoms des candidats au bac 2012
Tags: opendata

Je poursuis mon analyse des prénoms des candidats au bac cette année (voir
[billet précédent](http://cyrille.rossant.net/prenoms-et-reussite-au-bac/)) en
m'intéressant cette fois à la fréquence des différents prénoms portés
par les candidats, indépendamment de leurs résultats. Les 346 581
candidats portent 18 473 prénoms différents. **Le prénom le plus porté
est Camille** avec 4 848 candidats. Voici les quelques prénoms les plus
utilisés, représentatifs des prénoms à la mode aux alentours de l'année
1994 (nuage réalisé sur [Wordle](http://www.wordle.net)).






    :::text
    Camille     4848
    Marie       4354
    Thomas      4134
    Manon       4131
    Nicolas     3851
    Alexandre   3831
    Maxime      3720
    Laura       3702
    Marine      3639
    Pauline     3630
    Marion      3433
    Antoine     3370
    Julie       3157
    Mathilde    3045
    Quentin     3036
    Guillaume   2913
    Pierre      2872
    Julien      2854
    Kevin       2835
    Lea         2780
    Anais       2775
    Romain      2621
    Clement     2615
    Melanie     2576
    Justine     2564
    Sarah       2398
    Florian     2298
    Chloe       2256
    Charlotte   2172
    Valentin    2150

Une observation intéressante est que les prénoms rares sont,
paradoxalement, très nombreux. Ainsi, 12 129 prénoms soit **65% de tous
les prénoms ne sont portés que par un seul candidat**! Mais ces
candidats ne représentent que 3.5% du total des candidats. Un nombre
important de parents souhaite ainsi donner un prénom unique à leur
enfant, souvent d'ailleurs en trouvant des variantes orthographiques
originales de prénoms plus classiques. Par exemple, le prénom Zinedine
admet comme variantes, entre
autres: Zin-Eddine, Zine-Din, Zine-Dine, Zine-Eddine, Zineddine
ou Zinnedine. D'ailleurs, **les prénoms composés représentent 15% de
tous les prénoms** (et 2% de tous les candidats).

Poursuivant le raisonnement, on peut s'intéresser au nombre de prénoms
portés par 2, 3, 4 candidats ou plus. Cela revient à étudier la
distribution des fréquences des prénoms. On obtient alors la courbe
suivante.



A gauche est représenté la fraction de prénoms qui sont portés par 1, 2,
... jusqu'à 20 candidats (points bleus). Si 65% des prénoms sont portés
par un seul candidat, 10% le sont par 2 candidats, 5% le sont par 3,
etc. Cette courbe démarre à une valeur importante mais diminue ensuite
extrêmement rapidement. Il s'agit d'une propriété caractéristique de
nombreux phénomènes et qui porte le nom de [**"longue
traîne"**](http://fr.wikipedia.org/wiki/Longue_tra%C3%AEne).
L'utilisation des mots dans une langue donnée, la répartition des
richesses, la population dans les villes constituent quelques exemples.
Il y a ainsi très peu de villes extrêmement peuplées, et énormément de
villes très peu peuplées, de telle sorte qu'environ 20% de toutes les
villes représentent 80% de la population. Ou encore, 20% d'une
population concentre 80% des richesses. C'est [**la loi des 80-20, ou
principe de Pareto**](http://fr.wikipedia.org/wiki/Principe_de_Pareto),
qui quantifie en quelque sorte certaines inégalités.

Ici, **ce principe est approximativement vérifié qualitativement mais
non quantitativemen**t: il est en fait plus marqué que la règle des
80-20! Ainsi 80% des candidats sont représentés non pas par 20% des
prénoms, mais par 2.5%! **Au delà de l'observation d'un grand nombre de
prénoms rares, on peut faire celle d'un petit nombre de prénoms très
répandus**. Ainsi, seuls 0.5% des prénoms servent à nommer la moitié des
candidats. De plus, **10% des prénoms représentent 90% des candidats**,
formant ainsi plutôt une règle des 90-10.

Mathématiquement, on peut constater que **la distribution des fréquences
des prénoms semble suivre de manière assez approximative une [loi de
Zipf](http://fr.wikipedia.org/wiki/Loi_de_Zipf)**, typique d'une
distribution à longue traîne et satisfaisant à une règle de type 80-20.
Cette loi signifie que le nombre de prénoms donné à $n$
candidats est proportionnel à $1/n^s$, avec
$s>1$ un paramètre réel (loi de puissance). On constate en
effet que la distribution des fréquences des prénoms dans un [graphique
log-log](http://en.wikipedia.org/wiki/Log-log_plot) est
approximativement linéaire, suggérant une loi de puissance
(voir panneau de droite dans la figure précédente). On peut tenter de
faire correspondre une loi de Zipf à ces données, à l'aide d'une méthode
d'estimation statistique. En utilisant la [méthode du maximum de
vraisemblance](http://fr.wikipedia.org/wiki/Maximum_de_vraisemblance),
on trouve une valeur $s \simeq 1.9$ pour le paramètre.
Cette distribution adaptée aux données est représentée en rouge dans la
figure précédente.

Une autre manière de représenter cette distribution est d'afficher le
pourcentage de candidats couverts par 1, 2, 3... prénoms, en triant les
prénoms par ordre décroissant de fréquence. On obtient le graphique
suivant (à droite, échelle log-log) :



Le "coude" observé à gauche est typique d'une loi de Zipf. De gauche à
droite, les prénoms sont classés par fréquence décroissante (le prénom
le plus donné d'abord, Camille, puis le second, Marie, etc.). Au fur et
à mesure que l'on ajoute ces prénoms, la fraction de candidats
représentés augmente très rapidement (partie gauche du coude). Puis
viennent les prénoms beaucoup plus rares, portés par un nombre très
faible de candidats (partie droite). La courbe croît alors très
lentement, le nombre de candidats couverts n'augmentant que d'une
fraction infinitésimale à chaque prénom.

La répartition des prénoms est ainsi particulièrement hétérogène, avec
d'un côté des prénoms très répandus, et de l'autre côté des prénoms
totalement originaux, nouveaux, ou uniques. Y aurait-il deux grandes
tendances chez les parents, entre les "traditionalistes" qui
souhaiteraient utiliser des prénoms classiques (ou des prénoms
d'ascendants familiaux), et les "modernistes" qui souhaiteraient rompre
avec le passé et marquer leur originalité? Notons qu'il est possible de
concilier les deux tendances, en quelque sorte, en [utilisant un prénom
du passé en second prénom, comme pour manifester un lien avec les
générations
précédentes](http://coulmont.com/blog/2011/07/20/le-vieux-qui-hante/).
Par ailleurs, cette tendance observée dans une population très
spécifique (une partie des candidats au bac 2012) est-elle la même que
celle observée plus généralement dans toute la population? Je laisse le
soin aux [sociologues](http://coulmont.com/) d'y répondre.

---

## File: content/2012-08-19-a-mathematical-proof-that-our-world-is-in-three-dimensions.md

Title: A mathematical proof that our world is in three dimensions
Tags: maths

Everyone knows that our world is three-dimensional. It seems indeed obvious that there are three independent spatial directions, no less, no more. But can we really be sure? After all, everything we know about our world comes from our senses and from what our brains interprete. Does the fact that we _see_ in 3D really proves that the world _is_ in 3D? Can we have a mathematical proof, based on experimental observations, that the world is three-dimensional? This question is totally relevant, and several scientists and philosophers, like [Immanuel Kant](http://en.wikipedia.org/wiki/Immanuel_Kant), have been interested in it (see for example [this blog post](http://webinet.cafe-sciences.org/articles/dans-combien-de-dimensions-vivons-nous/) in French for a nice review).



Here, I detail Kant's idea of a rigourous proof that we live in a 3D world. There are three steps:

1. We model the world as an N-dimensional Euclidean space and we study a mathematical object called a **vector field** that verifies some natural properties.
2. We find experimental observations that allows us to infer properties about this object.
3. We link these properties to the number of spatial dimensions and we conclude that $N=3$.

The physical notions behind this proof are about [conservative forces](http://en.wikipedia.org/wiki/Conservative_force) and [potential theory](http://en.wikipedia.org/wiki/Potential_theory). The mathematical notions concern the [Laplace operator](http://en.wikipedia.org/wiki/Laplace_operator) and [harmonic functions](http://en.wikipedia.org/wiki/Harmonic_function).

First, here is an intuitive explanation of this proof ([quoting Wikipedia](http://en.wikipedia.org/wiki/Inverse-square_law#Justification)):

> The inverse-square law generally applies when some force, energy, or other conserved quantity is radiated outward radially in three-dimensional space from a point source. Since the surface area of a sphere (which is $4\pi r^2$) is proportional to the square of the radius, as the emitted radiation gets farther from the source, it is spread out over an area that is increasing in proportion to the square of the distance from the source. Hence, the intensity of radiation passing through any unit area (directly facing the point source) is inversely proportional to the square of the distance from the point source.

1. Mathematical model
---------------------
We model the world as an open set $U$ of $\mathbb R^N$, where $N$ is the number of dimensions. We consider a [**vector field**](http://en.wikipedia.org/wiki/Vector_field) $F$, that is, a function $F: U \longrightarrow \mathbb R^N$ that maps any point $p$ in $U$ to a $N$-dimensional vector attached to that point. This vector field can represent a [force field](http://en.wikipedia.org/wiki/Force_field_(physics)), like a [gravitational field](http://en.wikipedia.org/wiki/Gravitational_field) generated by a massive object, or an [electrostatic field](http://en.wikipedia.org/wiki/Electric_field) generated by a charged body. It can also represent a [**flux**](http://en.wikipedia.org/wiki/Flux), like in [transport phenomena](http://en.wikipedia.org/wiki/Transport_phenomena): [heat transfer](http://en.wikipedia.org/wiki/Heat_transfer), [mass transfer](http://en.wikipedia.org/wiki/Mass_transfer) or [fluid dynamics](http://en.wikipedia.org/wiki/Fluid_dynamics).

We will assume three natural hypotheses: that this vector field is [**incompressible**](http://en.wikipedia.org/wiki/Solenoidal_vector_field) (or solenoidal), [**conservative**](http://en.wikipedia.org/wiki/Conservative_vector_field) (or irrotational), and [**isotropic**](http://en.wikipedia.org/wiki/Isotropy). One also uses the terminology of [**Laplacian vector field**](http://en.wikipedia.org/wiki/Laplacian_field) when the first two hypotheses are satisfied. These hypotheses correspond to a conserved quantity that is radiated outward radially and isotropically from a point source.

**Incompressibility** occurs when the [**divergence**](http://en.wikipedia.org/wiki/Divergence) of the vector field is zero: $\nabla \cdot F=0$. It means that there is no local source or sink, no local creation or annihilation. If the vector field represents a mass transfer, incompressibility means that there is conservation of mass: mass cannot be created or annihilated at any point in space. For a gravitational field, the divergence is zero outside mass sources. Similarly, for an electrostatic field, the divergence is zero outside charge sources.

**Irrotationality** occurs when the [**curl**](http://en.wikipedia.org/wiki/Curl_(mathematics)) of the vector field is zero: $\nabla \times F=0$. It means that the field does not _spin_ locally (in fluid dynamics terms, there is no [vorticity](http://en.wikipedia.org/wiki/Vorticity)). An equivalent property is that the field is **conservative**, so that the line integral from one point to another is independent of the choice of path connecting the two points (in fact, one has to assume the _simple connectedness_ of $U$ for the equivalence). A conservative field is the **[gradient](http://en.wikipedia.org/wiki/Gradient) of a scalar field**: there exists a scalar field $u : U \longrightarrow \mathbb R$ such that $F = \nabla u$. The gravitational force and the electrostatic force are examples of [conservative forces](http://en.wikipedia.org/wiki/Conservative_force). The gravitational _vector field_ is the gradient of the gravitational _potential field_, and similarly for the electrostatic field.

Finally, **isotropy** means uniformity in spatial directions, that is, we assume that the vector field $F$ is [rotational invariant](http://en.wikipedia.org/wiki/Rotational_invariance). For example, the gravitational or electrostatic field generated by a perfectly spherical source is rotational invariant.

Under the two last hypotheses, we can write $F=\nabla u(r)$ where $r$ is the distance to the origin: $r^2 = \sum x_i^2$. The vector field $F$ is the gradient of a scalar field $u$ that depends only on $r$ since it is isotropic. The first hypothesis, $\nabla \cdot F=0$ (outside field sources), implies that $\nabla \cdot \nabla u=0$, that is, $\Delta u=0$ where $\Delta=\sum \frac{\partial^2}{\partial x_i^2}$ is the [Laplacian](http://en.wikipedia.org/wiki/Laplace_operator).

The equation $\Delta u=0$ is a [**partial differential equation**](http://en.wikipedia.org/wiki/Partial_differential_equation) (PDE) called the [**Laplace equation**](http://en.wikipedia.org/wiki/Laplace%27s_equation). A function with a null Laplacian is called an [**harmonic function**](http://en.wikipedia.org/wiki/Harmonic_function), so we're looking for an harmonic function $u(r)$. 


2. Experimental observations
----------------------------
It is known since [Newton](http://en.wikipedia.org/wiki/Newton's_law_of_universal_gravitation) and [Coulomb](http://en.wikipedia.org/wiki/Coulomb's_law) that the laws of gravitation and electrostatics follow [inverse-square laws](http://en.wikipedia.org/wiki/Inverse-square_law), where the strength of interaction forces is proportional to the inverse square of the distance. This observation has been validated by a number of experiments during the last centuries. The same inverse-square law is observed for light, sound and radiation phenomena.

We will now show that if a vector field satisfying the three preceding properties (like the gravitation law) verifies the inverse-square law, then it implies necessarily that $N=3$, i.e. the world has three dimensions.

3. Proof
--------
The proof is straightforward once one knows the following [expression for the Laplacian in N dimensions and in spherical coordinates](http://en.wikipedia.org/wiki/Laplace_operator#N_dimensions):

$$\Delta u(r) = \frac{1}{r^{N-1}} \times \frac{\partial}{\partial r} \left( r^{n-1} \frac{\partial u}{\partial r} \right) + \frac{1}{r^2} \times \Delta_{S^{N-1}} u$$

where $\Delta_{S^{N-1}}$ is the [Laplace-Beltrami operator](http://en.wikipedia.org/wiki/Laplace%E2%80%93Beltrami_operator) on the [(N-1)-hypersphere](http://en.wikipedia.org/wiki/N_sphere) (an (N-1)-dimensional [Riemannian manifold](http://en.wikipedia.org/wiki/Riemannian_manifold)), also called [spherical Laplacian](http://en.wikipedia.org/wiki/Laplace%E2%80%93Beltrami_operator#Examples).

Since $u$ is isotropic and depends only on $r$, it is constant on hyperspheres (defined by $r=\textrm{constant}$), so that the restriction of $u$ on $S^{N-1}$ is constant, its gradient is null, and $\Delta_{S^{N-1}} u=0$. Therefore:

$$\frac{1}{r^{N-1}} \times \frac{\partial}{\partial r} \left( r^{n-1} \frac{\partial u}{\partial r} \right) = 0$$

hence:

$$\left( r^{n-1} \frac{\partial u}{\partial r} \right) = \textrm{constant}$$

and finally we find that:

$$u(r) = \frac{C}{r^{N-2}}.$$

We omit the integration constant since a potential field is defined up to an additive constant. Hence, the intensity of the vector field $\nabla u$ is proportional to $1/r^{N-1}$. For an inverse-square law, it means that $N-1=2$ so that $N=3$.

Finally, we should add that some modern theories, like [string theory](http://en.wikipedia.org/wiki/String_theory), assume a higher number of spatial dimensions, where the extra dimensions are of a much smaller scale, such that, at common scales, the three dimensions of space are still a reasonable approximation.

---

## File: content/2012-09-16-pyopencl-on-windows-without-a-gpu.md

Title: A PyOpenCL tutorial on Windows with or without a GPU
Tags: python, gpu

I've been using [CUDA](http://en.wikipedia.org/wiki/CUDA) and 
[PyCUDA](http://documen.tician.de/pycuda/) as 
[GPGPU](http://en.wikipedia.org/wiki/GPGPU) platforms for a few years now. 
They enable access to the incredible computational power of graphics cards 
through a simple C-like language. A recent 
[Nvidia](http://en.wikipedia.org/wiki/Nvidia) graphics card is nevertheless 
required in order to execute CUDA code. Some computers may not include a 
Nvidia GPU, but rather an 
[AMD/ATI](http://en.wikipedia.org/wiki/Advanced_Micro_Devices) card or even 
an integrated graphics processor. Those computers thus cannot execute a CUDA 
program.



Whereas changing the GPU on a desktop computer is straightforward (one still 
needs to buy a new graphics card...), it is generally not possible to do so 
on a laptop. It prevents a number of developers to run, compile or debug CUDA 
code. It is also certainly a problem when distributing a software relying on 
CUDA, since not having a CUDA-enabled Nvidia GPU prevents one to even launch 
the program.

For these reasons, I've recently been interested in 
[OpenCL](http://en.wikipedia.org/wiki/OpenCL), a computing framework 
equivalent to CUDA. The main difference is that OpenCL is an open standard 
that has been adopted not only by Nvidia, but also by Intel and AMD. It means 
that OpenCL programs may run on (recent) graphics card of either Nvidia or 
AMD. In addition, a very interesting feature is that OpenCL programs may run 
on a computer that does not even have a OpenCL-enabled GPU, but only a 
recent-enough CPU. OpenCL code can be compiled for CPUs through the [Intel 
SDK for OpenCL](http://software.intel.com/en-us/vcsource/tools/opencl-sdk) 
(Intel-only CPUs) or the [AMD APP 
SDK](http://developer.amd.com/tools/hc/AMDAPPSDK/). OpenCL code is still 
accelerated through vectorization instructions on CPUs (e.g. 
[SSE](http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions) or 
[AVX](http://en.wikipedia.org/wiki/Advanced_Vector_Extensions)) and multicore 
CPUs.

This is really convenient since one can develop, debug and run an OpenCL 
program on virtually any computer, even if it does not include an 
OpenCL-enabled GPU. Moreover, distributing such a program is easier since the 
end-user does not necessarily need to have a specific graphics card. Of 
course, the performance of the program will be far less interesting than with 
such a GPU, but the program will still run correctly.

Here I detail my first experience with OpenCL on Python (using 
[PyOpenCL](http://mathema.tician.de/software/pyopencl)).
The installation part is actually the less trivial part (while still being
relatively easy) and may be of interest to some people.

Installation of an OpenCL SDK
-----------------------------

I'll explain how I could install OpenCL and PyOpenCL on an "old" laptop with 
an [ATI Radeon Mobility HD 
3650](http://www.amd.com/us/products/desktop/graphics/ati-radeon-hd-3000/hd-3600)
graphics card that does not support 
OpenCL, an [Intel Core 2 Duo CPU](http://en.wikipedia.org/wiki/Intel_Core_2), 
and a 32-bits [Windows 8](http://en.wikipedia.org/wiki/Windows_8) operating 
system.

First, one needs to install an OpenCL SDK. AMD and Intel have their own SDKs 
and I installed both. Later, we'll see that PyOpenCL allows us to choose, at 
compilation-time, which SDK to use. The installation of the SDKs is 
straightforward on Windows.

Installation of PyOpenCL
------------------------

PyOpenCL is to OpenCL what PyCUDA is to CUDA: a Python wrapper to those GPGPU 
platforms. It is developed and maintained by [Andreas 
Klöckner](http://mathema.tician.de/). 

Installing PyOpenCL on Windows is easy when using the binary package provided 
by [Christoph Gohlke](http://www.lfd.uci.edu/~gohlke/). [His 
webpage](http://www.lfd.uci.edu/~gohlke/pythonlibs/) contains Windows binary 
installers for the most recent versions of hundreds of Python packages. It is 
of invaluable help for those Python users that use Windows. It is also 
possible yet much more complicated to build [PyOpenCL from source on 
Windows](http://wiki.tiker.net/PyOpenCL/Installation). 

PyOpenCL has a few uncommon dependencies (beyond 
[Numpy](http://numpy.scipy.org/)), like 
[decorator](http://pypi.python.org/pypi/decorator) and 
[PyTools](http://pypi.python.org/pypi/pytools) (actually the latter includes 
_decorator_, so I'm not even sure one needs to install decorator separately). 
These libraries can be easily installed with the `easy_install` command-line 
tool provided by the [Distribute](http://packages.python.org/distribute/) 
library. 

Some environment variables may need to be specified, like `PYOPENCL_CTX` or 
`PYOPENCL_COMPILER_OUTPUT` (see below). In order to do this, one needs to go 
to the advanced system parameters and add new variables in the _User 
variables_ section ([see 
here](http://www.technoon.com/how-to-add-environment-variables-in-windows-8.html)
for details). 

In order to quickly test the installation of PyOpenCL, try the following 
commands in a Python console:

    import pyopencl
    import pyopencl.array

We now turn to the execution of a very simple OpenCL program.

PyOpenCL Hello World script
---------------------------

Save the following code in a .py file and execute it. The OpenCL code should be 
compiled and executed correctly, and the squares of integers should be
displayed. Some warnings may be displayed even if everything worked corectly.
In addition, PyOpenCL may require the user to decide which SDK to use if several
are installed. In order not to be asked everytime, one can set the
`PYOPENCL_CTX` environment variable to the corresponding index (see above).

I could use both Intel and AMD SDKs. Ensure that you run Python in a command
line as an administrator (otherwise it may cause issues with
compilation, at least that's what I could note on my Windows 8 setup).

The actual code is self-explanatory, especially for someone who already knows
CUDA. This program generates a Numpy array with all integers between 0 and 9,
passes it to an OpenCL kernel that computes the square of an array of integers,
dynamically compiles and executes this kernel, and copies back the output from
the context memory to Python.

    # import PyOpenCL and Numpy. An OpenCL-enabled GPU is not required,
    # OpenCL kernels can be compiled on most CPUs thanks to the Intel SDK for OpenCL
    # or the AMD APP SDK.
    import pyopencl as cl
    import numpy as np

    # create an OpenCL context
    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)

    # create the kernel input
    a = np.array(np.arange(10), dtype=np.int32)

    # kernel output placeholder
    b = np.empty(a.shape, dtype=np.int32)

    # create context buffers for a and b arrays
    # for a (input), we need to specify that this buffer should be populated from a
    a_dev = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, 
                        hostbuf=a)
    # for b (output), we just allocate an empty buffer
    b_dev = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, b.nbytes)

    # OpenCL kernel code
    code = """
    __kernel void test1(__global int* a, __global int* b) {
        int i = get_global_id(0);
        b[i] = a[i]*a[i];
    }
    """

    # compile the kernel
    prg = cl.Program(ctx, code).build()

    # launch the kernel
    event = prg.test1(queue, a.shape, a_dev, b_dev)
    event.wait()

    # copy the output from the context to the Python process
    cl.enqueue_copy(queue, b, b_dev)

    # if everything went fine, b should contain squares of integers
    print(b)

Here is the output I get on my installation.

	:::text
    C:\Python27\lib\site-packages\pyopencl\__init__.py:32: CompilerWarning: Built kernel retrieved from cache. Original from-source build had warnings:
    Build on  succeeded, but said:

    Build started
    Kernel <test1> was successfully vectorized
    Done.
      warn(text, CompilerWarning)
    C:\Python27\lib\site-packages\pyopencl\__init__.py:32: CompilerWarning: From-binary build succeeded, but resulted in non-empty logs:
    Build on  succeeded, but said:

    Build started
    Kernel <test1> was successfully vectorized
    Done.
      warn(text, CompilerWarning)
    [ 0  1  4  9 16 25 36 49 64 81]
    
Final notes
-----------

There is of course far more to tell about OpenCL that what I've shown here. 
The point was to show how one could use GPGPU on a standard computer that 
does not have a GPGPU-enabled graphics card, by using OpenCL and Python.
Even if I don't have much experience in OpenCL yet, I think it has a promising
future as an open and portable concurrent to CUDA.

Here are some interesting related links:

*   [The official OpenCL website](http://www.khronos.org/opencl/)
*   [PyOpenCL tutorial](http://enja.org/2011/02/22/adventures-in-pyopencl-part-1-getting-started-with-python/)
*   [Another one (in French)](http://www.planquart.com/tutoriel-n%C2%B01-pyopencl-premier-calcul-sur-gpu)