Qu'est-ce que Julia? Une nouvelle approche du calcul numérique

Julia est un langage de programmation dynamique open source, de haut niveau et de haute performance pour le calcul numérique. Il a la commodité de développement d'un langage dynamique avec les performances d'un langage compilé à typage statique, en partie grâce à un compilateur JIT basé sur LLVM qui génère du code machine natif, et en partie à une conception qui implémente la stabilité de type grâce à la spécialisation via plusieurs dispatch, ce qui facilite la compilation en code efficace.

Dans le billet de blog annonçant la sortie initiale de Julia en 2012, les auteurs du langage - Jeff Bezanson, Stefan Karpinski, Viral Shah et Alan Edelman - ont déclaré avoir passé trois ans à créer Julia parce qu'ils étaient gourmands . Ils étaient fatigués des compromis entre Matlab, Lisp, Python, Ruby, Perl, Mathematica, R et C, et voulaient un langage unique qui serait bon pour le calcul scientifique, l'apprentissage automatique, l'exploration de données, l'algèbre linéaire à grande échelle. , l'informatique parallèle et l'informatique distribuée.

Pour qui est Julia? En plus d'être attrayante pour les chercheurs et les ingénieurs, Julia est également attrayante pour les scientifiques des données et pour les analystes financiers et les quants.

Les concepteurs du langage et deux autres ont fondé Julia Computing en juillet 2015 pour «développer des produits qui rendent Julia facile à utiliser, facile à déployer et à faire évoluer». Au moment de la rédaction de cet article, la société compte 28 employés et des clients allant des laboratoires nationaux aux banques en passant par les économistes et les chercheurs sur les véhicules autonomes. En plus de gérer les référentiels open source Julia sur GitHub, Julia Computing propose des produits commerciaux, notamment JuliaPro, qui est disponible en versions gratuite et payante.

Pourquoi Julia?

Julia «vise à créer une combinaison sans précédent de facilité d'utilisation, de puissance et d'efficacité dans une seule langue.» Pour la question de l'efficacité, considérez le graphique ci-dessous:

Julia Computing

Benchmarks de Julia

Ce que nous voyons ici, c'est que le code Julia peut être plus rapide que C pour quelques types d'opérations, et pas plus de quelques fois plus lent que C pour d'autres. Comparez cela à, disons, R, qui peut être presque 1 000 fois plus lent que C pour certaines opérations.

Notez que l'un des tests les plus lents pour Julia est la récursivité de Fibonacci; c'est parce que Julia n'a actuellement pas d'optimisation de récursivité de queue. La récursivité est intrinsèquement plus lente que la boucle. Pour les vrais programmes Julia que vous souhaitez exécuter en production, vous voudrez implémenter la forme de boucle (itération) de ces algorithmes.

Compilation Julia JIT

Il y a un coût pour l'approche du compilateur JIT (juste à temps) par opposition à un interpréteur pur: le compilateur doit analyser le code source et générer du code machine avant que votre code puisse s'exécuter. Cela peut signifier un temps de démarrage notable pour les programmes Julia la première fois que chaque fonction et macro s'exécute dans une session. Ainsi, dans la capture d'écran ci-dessous, nous voyons que la deuxième fois que nous générons un million de nombres à virgule flottante aléatoires, le temps pris est d'un ordre de grandeur inférieur à celui de la première exécution. La @timemacro et la rand()fonction devaient être compilées la première fois dans le code, car les bibliothèques Julia sont écrites en Julia.

julia> @time rand (10 ^ 6);

  0,62081 secondes (14,44 k allocations: 8,415 Mio)

julia> @time rand (10 ^ 6);

  0,004881 seconde (7 allocations: 7,630 Mio)

Les fans de Julia affirment, à plusieurs égards, qu'il a la facilité d'utilisation de Python, R ou même Matlab. Ces comparaisons méritent d'être examinées, car le langage Julia est élégant, puissant et orienté vers l'informatique scientifique, et les bibliothèques fournissent un large éventail de fonctionnalités de programmation avancées.

Exemple de Julia

Comme exemple de langage Julia rapide, considérez le code de référence d'ensemble Mandelbrot suivant:

Comme vous pouvez le voir, l'arithmétique des nombres complexes est intégrée au langage, tout comme les macros pour les tests et le chronométrage. Comme vous pouvez également le voir, les points-virgules de fin qui infestent les langages de type C et les parenthèses imbriquées qui infestent les langages de type Lisp sont absents de Julia. Notez qu'il mandelperf()est appelé deux fois, aux lignes 61 et 62. Le premier appel teste l'exactitude du résultat et effectue la compilation JIT; le deuxième appel obtient le timing.

Programmation Julia

Julia a de nombreuses autres fonctionnalités à mentionner. D'une part, les types définis par l'utilisateur sont aussi rapides et compacts que les types intégrés. En fait, vous pouvez déclarer des types abstraits qui se comportent comme des types génériques, sauf qu'ils sont compilés pour les types d'arguments qu'ils sont passés.

D'autre part, la vectorisation de code intégrée de Julia signifie qu'il n'y a pas besoin d'un programmeur pour vectoriser le code pour les performances; le code dévectorisé ordinaire est rapide. Le compilateur peut tirer parti des instructions et des registres SIMD s'ils sont présents sur le processeur sous-jacent, et dérouler les boucles dans un processus séquentiel pour les vectoriser autant que le matériel le permet. Vous pouvez marquer les boucles comme vectorisables avec l' @simdannotation.

Parallélisme de Julia

Julia a également été conçue pour le parallélisme et le calcul distribué, en utilisant deux primitives: les références distantes et les appels distants. Les références à distance existent en deux versions:  Future et  RemoteChannel. A Futureest l'équivalent d'un JavaScript promise; a RemoteChannelest réinscriptible et peut être utilisé pour la communication inter-processus, comme un Unix pipeou un Go channel. En supposant que vous avez commencé à Julia avec plusieurs processus (par exemple julia -p 8pour un processeur à huit cœurs comme un processeur Intel Core i7), vous pouvez @spawnou les remotecall()appels de fonction d'exécuter un autre processus Julia de manière asynchrone, et plus tard fetch()le Futureretourné lorsque vous souhaitez synchroniser et utiliser la résultat.

Si vous n'avez pas besoin de fonctionner sur plusieurs cœurs, vous pouvez utiliser un thread léger «vert», appelé a Task()dans Julia et une coroutine dans d'autres langages. A Task()ou @taskfonctionne en conjonction avec a Channel, qui est la version à processus unique de RemoteChannel.

Système de type Julia

Julia a un système de type discret mais puissant qui est dynamique avec l'inférence de type au moment de l'exécution par défaut, mais permet des annotations de type facultatives. Ceci est similaire à TypeScript. Par exemple:

julia> (1 + 2) :: AbstractFloat

ERREUR: TypeError: typeassert: attendu AbstractFloat, obtenu Int64

julia> (1 + 2) :: Int

3

Ici, nous affirmons un type incompatible la première fois, provoquant une erreur, et un type compatible la deuxième fois.

Julia cordes

Julia prend en charge efficacement les chaînes et les caractères Unicode, stockés au format UTF-8, ainsi qu'une prise en charge efficace des caractères ASCII, car en UTF-8, les points de code inférieurs à 0x80 (128) sont codés en un seul caractère. Sinon, UTF-8 est un codage de longueur variable, vous ne pouvez donc pas supposer que la longueur d'une chaîne Julia est égale au dernier index de caractère.

La prise en charge complète de UTF-8 signifie, entre autres, que vous pouvez facilement définir des variables en utilisant des lettres grecques, ce qui peut faire ressembler le code scientifique de Julia aux explications des formules dans les manuels, par exemple sin(2π). Une transcode()fonction est fournie pour convertir UTF-8 vers et à partir d'autres encodages Unicode.

Fonctions C et Fortran

Julia peut appeler directement les fonctions C et Fortran, sans wrapper ni API spéciales, bien que vous ayez besoin de connaître le nom de la fonction «décorée» émis par le compilateur Fortran. La fonction externe C ou Fortran doit être dans une bibliothèque partagée; vous utilisez la ccall()fonction Julia pour l'appel réel. Par exemple, sur un système de type Unix, vous pouvez utiliser ce code Julia pour obtenir la valeur d'une variable d'environnement en utilisant la getenvfonction de la libc:

fonction getenv (var :: AbstractString)

     val = ccall ((: getenv, "libc"),

                 Cstring, (Cstring,), var)

     si val == C_NULL

         erreur ("getenv: variable non définie:", var)

     fin

     unsafe_string (val)

fin

julia> getenv ("SHELL")

"/ bin / bash"

Macros Julia

Julia a des macros de type Lisp, qui se distinguent des préprocesseurs de macro utilisés par C et C ++. Julia dispose également d'autres fonctionnalités de métaprogrammation, telles que la réflexion, la génération de code, des objets de symbole (par exemple :foo) et d'expression (par exemple :(a+b*c+1)) eval()et des fonctions générées. Les macros Julia sont évaluées au moment de l'analyse.

Les fonctions générées, par contre, sont développées lorsque les types de leurs paramètres sont connus, avant la compilation des fonctions. Les fonctions générées ont la flexibilité des fonctions génériques (telles qu'implémentées en C ++ et Java) et l'efficacité des fonctions fortement typées, en éliminant le besoin de distribution à l'exécution pour prendre en charge le polymorphisme paramétrique.

Prise en charge du GPU

Julia prend en charge le GPU en utilisant, entre autres, le package d'apprentissage en profondeur MXNet, la bibliothèque de tableaux GPU ArrayFire, l'algèbre linéaire cuBLAS et cuDNN et les bibliothèques de réseaux neuronaux profonds, et le cadre CUDA pour le calcul GPU à usage général. Les wrappers Julia et leurs bibliothèques respectives sont illustrés dans le diagramme ci-dessous.

Julia Computing

JuliaPro et Juno IDE

Vous pouvez télécharger la ligne de commande Julia open source gratuite pour Windows, MacOS, Linux générique ou FreeBSD générique à partir du site du langage Julia. Vous pouvez cloner le référentiel de code source Julia à partir de GitHub.

Vous pouvez également télécharger JuliaPro à partir de Julia Computing. En plus du compilateur, JuliaPro vous offre le Juno IDE basé sur Atom (illustré ci-dessous) et plus de 160 packages organisés, y compris la visualisation et le traçage.

Au-delà du contenu de JuliaPro gratuit, vous pouvez ajouter des abonnements pour l'assistance aux entreprises, la fonctionnalité de financement quantitatif, la prise en charge de bases de données et l'analyse de séries chronologiques. JuliaRun est un serveur évolutif pour un cluster ou un cloud.

Cahiers Jupyter et IJulia

En plus d'utiliser Juno comme IDE Julia, vous pouvez utiliser Visual Studio Code avec l'extension Julia (illustrée directement ci-dessous) et les blocs-notes Jupyter avec le noyau IJulia (illustrés dans les deuxième et troisième captures d'écran ci-dessous). Vous devrez peut-être installer des notebooks Jupyter pour Python 2 ou (de préférence) Python 3 avec Anaconda ou pip.

JuliaBox

Vous pouvez exécuter Julia dans des blocs-notes Jupyter en ligne à l'aide de JuliaBox (illustrée ci-dessous), un autre produit de Julia Computing, sans effectuer aucune installation sur votre ordinateur local. JuliaBox comprend actuellement plus de 300 packages, exécute Julia 0.6.2 et contient des dizaines de blocs-notes Jupyter tutoriels. La liste de niveau supérieur des dossiers du didacticiel est présentée ci-dessous. Le niveau gratuit d'accès JuliaBox vous donne des sessions de 90 minutes avec trois cœurs de processeur; l'abonnement personnel de 14 $ par mois vous donne des sessions de quatre heures avec cinq cœurs; et l'abonnement pro de 70 $ par mois vous offre des sessions de huit heures avec 32 cœurs. L'accès au GPU n'est pas encore disponible en juin 2018.

Forfaits Julia

Julia "marche comme Python, mais court comme C." Comme mon collègue Serdar Yegulalp l'a écrit en décembre 2017, Julia commence à défier Python pour la programmation de la science des données, et les deux langages présentent des avantages. Comme indication du soutien à maturation rapide de la science des données chez Julia, considérons qu'il existe déjà deux livres intitulés Julia for Data Science , l'un de Zacharias Voulgaris et l'autre d'Anshul Joshi, bien que je ne puisse pas parler de la qualité de l'un ou l'autre. une.

Si vous regardez les packages Julia les mieux notés de Julia Observer, illustrés ci-dessous, vous verrez un noyau Julia pour les ordinateurs portables Jupyter, le package graphique Gadfly (similaire à ggplot2dans R), une interface de traçage générique, plusieurs apprentissage en profondeur et machine des packages d'apprentissage, des solveurs d'équations différentielles, des DataFrames, des modèles d'équilibre général stochastique dynamique (DSGE) de la Fed de New York, un langage de modélisation d'optimisation et des interfaces vers Python et C ++. Si vous allez un peu plus loin dans cette liste générale, vous trouverez également QuantEcon, PyPlot, ScikitLearn, un package bioinformatique, et une implémentation de lazy lists pour la programmation fonctionnelle.

Si les packages Julia ne suffisent pas à vos besoins et que l'interface Python ne vous mène pas là où vous voulez aller, vous pouvez également installer un package qui vous donne des interfaces génériques vers R (RCall) et Matlab.

Julia pour les analystes financiers et les quants

Les quants et les analystes financiers trouveront de nombreux packages gratuits pour accélérer leur travail, comme le montre la capture d'écran ci-dessous. En outre, Julia Computing propose la suite JuliaFin, composée de Miletus (un DSL pour les contrats financiers),  JuliaDB (une base de données en mémoire et distribuée haute performance),  JuliaInXL (appelez Julia à partir de feuilles Excel) et la  connectivité Bloomberg (accès à -heure et données de marché historiques).