IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

danielhagnoul

Julia. Opérateurs dot, pipe et composition.

Noter ce billet
par , 29/01/2021 à 12h05 (619 Affichages)
Le 2021-01-29, j'utilise Julia_1.5.3 sur VS_Code_1.52.1. Ordinateur : W10 Pro, i9-10900F.
Préalables, mes billets précédents sur Julia sont supposés connus et assimilés.

Opérateur dot

Documentation en anglais :

  1. Vectorized "dot" operators
  2. Dot Syntax for Vectorizing Functions


Pour chaque opération binaire comme ^, il y a une opération "point" correspondante .^ qui est automatiquement définie pour effectuer ^ élément par élément sur les tableaux. Par exemple [1,2,3] ^ 3 n'est pas défini, car il n'y a pas de signification mathématique standard pour "cuber" un tableau (non carré), mais [1,2,3] .^ 3 est défini comme le calcul du résultat élément par élément (ou "vectorisé") [1^3, 2^3, 3^3]. La combinaison d'opérateurs de points avec des littéraux numériques peut être ambiguë. Par exemple, il n'est pas clair si 1.+x signifie 1. + x ou 1 .+ x. Par conséquent, cette syntaxe n'est pas autorisée et des espaces doivent être utilisés autour de l'opérateur dans de tels cas.

Dans les langages de calcul technique, il est courant d'avoir des versions "vectorisées" de fonctions, qui appliquent simplement une fonction donnée f(x) à chaque élément d'un tableau A pour produire un nouveau tableau via f(A). Toute fonction de Julia f peut être appliquée élément par élément à n'importe quel tableau (ou autre collection) avec la syntaxe f.(A). Bien sûr, vous pouvez omettre le point si vous écrivez une méthode "vectorielle" spécialisée de f, par exemple via f(A::AbstractArray) = map(f, A), et c'est tout aussi efficace que f.(A). L'avantage de la syntaxe f.(A) est que les fonctions qui peuvent être vectorisées n'ont pas besoin d'être décidées à l'avance par le rédacteur de la bibliothèque.

Code Julia : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function main()
    f(x,y) = 3x + 4y
 
    X = [1.0, 2.0, 3.0]
    Y = [4.0, 5.0, 6.0]
 
    @time @show f.(X, Y)
    @time @show f.(X, Y)
end
 
main()
 
#=
La première mesure tient compte du temps de compilation
f.(X, Y) = [19.0, 26.0, 33.0]
  0.214062 seconds (412.58 k allocations: 21.876 MiB, 2.26% gc time)
 
f.(X, Y) = [19.0, 26.0, 33.0]
  0.000113 seconds (28 allocations: 2.312 KiB)
=#

Code Julia : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function main()
    #=
    L'opérateur dot peut combiner des tableaux et des scalaires, des 
    tableaux de la même taille (en effectuant l'opération élément 
    par élément), et même des tableaux de formes différentes 
    (par exemple en combinant des vecteurs ligne et colonne pour 
    produire une matrice). 
    =#
    v_ligne = [1.0 2.0 3.0]
    v_col = [5.0, 5.0, 5.0]
    @time @show v_ligne .+ v_col
    @time @show v_ligne .+ v_col
 
    v = [1.0, 2.0]
    m = [5.0 5.0 5.0 5.0; 6.0 6.0 6.0 6.0]
 
    @time @show v .+ m
 
    #=
    Si vous calculez 2 .* A .^2 .+ sin.(A) pour un tableau A, il 
    effectue une seule boucle A, calculant 2a^2 + sin(a) pour 
    chaque élément de A.
    =#
    A = [3.0, 6.0, 9.0]
    @time println("2 .* A .^2 .+ sin.(A) = $(2 .* A .^2 .+ sin.(A))")
 
    # Les appels de points imbriqués comme f.(g.(x)) sont fusionnés
    @time println("sqrt.(log10.(A)) = $(sqrt.(log10.(A)))")
 
    #=
    Il existe une macro dot (@.) qui permet de simplifier l'écriture 
    lorsque vous savez ce que vous faites en l'utilisant. Je crois 
    qu'il est préférable de commencer à utiliser dot sans elle.
    =#
    @time println("@. 2A^2 + sin(A) = $(@. 2A^2 + sin(A))")
end
 
main()
 
#=
La première mesure tient compte du temps de compilation
v_ligne .+ v_col = [6.0 7.0 8.0; 6.0 7.0 8.0; 6.0 7.0 8.0]
  0.217286 seconds (413.79 k allocations: 21.913 MiB)
 
v_ligne .+ v_col = [6.0 7.0 8.0; 6.0 7.0 8.0; 6.0 7.0 8.0]
  0.000463 seconds (35 allocations: 4.547 KiB)
 
v .+ m = [6.0 6.0 6.0 6.0; 8.0 8.0 8.0 8.0]   
  0.000347 seconds (33 allocations: 4.109 KiB)
 
2 .* A .^2 .+ sin.(A) = [18.14112000805987, 71.72058450180107, 162.41211848524176]
  0.041482 seconds (3.07 k allocations: 172.266 KiB)
 
sqrt.(log10.(A)) = [0.6907396432228734, 0.8821288173411204, 0.9768533715145405]
  0.000233 seconds (23 allocations: 2.000 KiB)
  
@. 2A^2 + sin(A) = [18.14112000805987, 71.72058450180107, 162.41211848524176]  
  0.000044 seconds (23 allocations: 2.000 KiB)
=#

Composition et pipe

Documentation en anglais : Function composition and piping

Les fonctions de Julia peuvent être combinées en les composant (∘) ou en les enchaînant (chaînage, pipe : |>).

Vous utilisez l'opérateur de composition de fonction (∘) pour composer les fonctions, c'est donc (f ∘ g)(args...)la même chose que f(g(args...)). Vous pouvez saisir l'opérateur de composition dans la REPL et les éditeurs correctement configurés à l'aide de \circ<tab>.

Le chaînage de fonctions (parfois appelé "piping" ou "using a pipe" pour envoyer des données à une fonction ultérieure) consiste à appliquer une fonction à la sortie de la fonction précédente avec |>.

function main()
    @time @show (sqrt ∘ +)(3, 6)
    @time @show (sqrt ∘ +)(3, 6)

    @time @show map(first ∘ reverse ∘ uppercase, split("you can compose functions like this"))
    @time @show split("you can compose functions like this") .|> uppercase .|> reverse .|> first

    @time @show (sqrt ∘ sum)(1:10)
    @time @show 1:10 |> sum |> sqrt

    @time @show sum(sqrt.(1:10))
    @time @show 1:10 .|> sqrt |> sum
end

main()

#=
La première mesure tient compte du temps de compilation
(sqrt ∘ (+))(3, 6) = 3.0
  0.163357 seconds (409.03 k allocations: 21.682 MiB)

(sqrt ∘ (+))(3, 6) = 3.0
  0.000256 seconds (16 allocations: 832 bytes)

map((first ∘ reverse) ∘ uppercase, split("you can compose functions like this")) = 
['U', 'N', 'E', 'S', 'E', 'S']    
  0.084758 seconds (14.10 k allocations: 746.850 KiB)

((split("you can compose functions like this") .|> uppercase) .|> reverse) .|> first = 
['U', 'N', 'E', 'S', 'E', 'S']
  0.000074 seconds (45 allocations: 2.016 KiB)

(sqrt ∘ sum)(1:10) = 7.416198487095663
  0.000071 seconds (16 allocations: 848 bytes)

(1:10 |> sum) |> sqrt = 7.416198487095663
  0.000061 seconds (17 allocations: 1.156 KiB)

sum(sqrt.(1:10)) = 22.4682781862041
  0.000061 seconds (17 allocations: 1008 bytes)

(1:10 .|> sqrt) |> sum = 22.4682781862041
  0.000060 seconds (18 allocations: 1.312 KiB)
=#
function main()
    xs = [1.0, 2.0, 3.0, 4.0, 5.0]

    add(x) = x + 1.0
    mul(x) = 2.0x
    addmul(xs) = xs .|> add .|> mul

    @time @show addmul(xs)
    @time @show addmul(xs)

    @time @show sqrt.(2.0π .* xs)

    @time @show @. sqrt(2.0π * xs)
end

main()

#=
addmul(xs) = [4.0, 6.0, 8.0, 10.0, 12.0]
  0.213491 seconds (412.59 k allocations: 21.877 MiB, 2.27% gc time)

addmul(xs) = [4.0, 6.0, 8.0, 10.0, 12.0]
  0.000074 seconds (34 allocations: 3.203 KiB)

sqrt.((2.0π) .* xs) = [2.5066282746310002, 3.5449077018110318, 4.3416075273496055, 
5.0132565492620005, 5.604991216397929]
  0.000574 seconds (34 allocations: 3.109 KiB)

@__dot__(sqrt((2.0π) * xs)) = [2.5066282746310002, 3.5449077018110318, 
4.3416075273496055, 5.0132565492620005, 5.604991216397929]
  0.000082 seconds (34 allocations: 3.109 KiB)
=#
Licence Creative Commons Attribution 2.0 Belgique

Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Viadeo Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Twitter Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Google Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Facebook Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Digg Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Delicious Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog MySpace Envoyer le billet « Julia. Opérateurs dot, pipe et composition. » dans le blog Yahoo

Mis à jour 29/01/2021 à 17h15 par danielhagnoul

Catégories
Programmation , Julia

Commentaires