2017-05-29 1 views
2

Disons que j'ai une fonction nommée triglycéride, qui retourne deux sorties:Retour plusieurs valeurs d'une fonction mappée

function trig(x) 
    return(sin(x), cos(x)) 
end 

Si je veux évaluer TRIG sur de nombreuses valeurs, je peux utiliser la fonction carte:

julia> out = map(trig, (0:(pi/12):(pi/2))) 

out est un réseau d'éléments 7 et dans chaque élément, il y a un tuple contenant deux éléments:

julia> out 
7-element Array{Tuple{Float64,Float64},1}: 
(0.0,1.0) 
(0.258819,0.965926) 
(0.5,0.866025) 
(0.707107,0.707107) 
(0.866025,0.5) 
(0.965926,0.258819) 
(1.0,6.12323e-17) 

Mon qu estion est: Quelle est la meilleure façon de démêler mes sinus et cosinus de sorte que j'ai deux tableaux avec 7 éléments chacun? Est-il possible de diffuser trig sans créer le tableau superflu de tuples et créer directement les deux tableaux qui m'intéressent vraiment?

Pour le moment, j'invoque à nouveau la carte afin d'en extraire les valeurs de l'extérieur afin de remplir les tableaux que je veux, mais je ne pense pas que ce soit la meilleure façon de le faire:

sines = map(x->x[1], out) 
cosines = map(x->x[2], out) 

Pour les besoins de cette question, supposons que trig est une fonction coûteuse en calcul. Donc, s'il vous plaît ne me donnez pas une réponse qui nécessite d'être évalué plus d'une fois.

+0

Je ne pense pas qu'il y ait un moyen de le faire raisonnablement sans réallocation, puisque, par ex. '0.0' et' 0.258819' ne sont pas côte à côte en mémoire (le '1.0' est entre-deux). Pour le voir, utilisez 'reinterpret (Float64, out, (2, 7))', qui n'a pas de surcharge, mais notez que 'sines' est la première ligne de la matrice de sortie, et' cosines' est la deuxième ligne, et puisque les tableaux sont classés par ordre croissant de colonnes, l'extraction de 'sine's en tant que' Vector' * doit * déclencher la réallocation. En d'autres termes, je soupçonne 'map' d'être aussi efficace que de résoudre ceci ... –

+1

Sinon, fournissez simplement votre propre définition de méthode pour' trig' pour le cas d'entrée 'AbstractVector' et allouez la sortie des appels à la méthode 'trig' dans la question à deux vecteurs explicitement. Il y a probablement un one-liner intelligent pour le faire mais je ne peux pas le voir du haut de ma tête (ma version aurait une ligne de pré-allocation et une boucle explicite) –

+1

Voir aussi https://stackoverflow.com/q/44010033 et https://stackoverflow.com/q/41183481/6172490. – tim

Répondre

1

Merci de partager votre réponse à une question antérieure que j'ai dû ignorer dans ma recherche avant de poser celle-ci. Avant aujourd'hui, je ne l'avais jamais entendu parler de la fonction getIndex, mais il semble que GetIndex est la fonction que je veux, pour autant que je vectoriser en mettant un point devant:

julia> @time sine_map = map(x->x[1], out) 
    0.051494 seconds (13.32 k allocations: 602.941 KB) 
7-element Array{Float64,1}: 
0.0 
0.258819 
0.5 
0.707107 
0.866025 
0.965926 
1.0 

julia> @time sine_geti = getindex.(out, 1) 
    0.029560 seconds (9.24 k allocations: 416.910 KB) 
7-element Array{Float64,1}: 
0.0 
0.258819 
0.5 
0.707107 
0.866025 
0.965926 
1.0 

julia> @time cosine_map = map(x->x[2], out) 
    0.037328 seconds (13.32 k allocations: 602.941 KB) 
7-element Array{Float64,1}: 
1.0 
0.965926 
0.866025 
0.707107 
0.5 
0.258819 
6.12323e-17 

julia> @time cosey_geti = getindex.(out, 2) 
    0.024785 seconds (9.24 k allocations: 416.910 KB) 
7-element Array{Float64,1}: 
1.0 
0.965926 
0.866025 
0.707107 
0.5 
0.258819 
6.12323e-17 

La réduction du nombre d'allocations de 30% Il n'y a rien à éternuer. Je vous remercie.

Je pense que je suis Sécurisant ce encore plus concise:

@time sines, cosines = map(x->getindex.(out, x), 1:2) 
    0.062047 seconds (20.81 k allocations: 956.831 KB) 
2-element Array{Array{Float64,1},1}: 
[0.0,0.258819,0.5,0.707107,0.866025,0.965926,1.0] 
[1.0,0.965926,0.866025,0.707107,0.5,0.258819,6.12323e-17] 

Et vous remercie Colin T Bowers pour suggérer que je peux définir une méthode personnalisée pour TRIG. Je vais certainement envisager de le faire si getindex ne parvient pas à fournir la performance que je veux.

+0

Vous pouvez essayez 'sines, cosines = map (collecter, zip (out ...))' aussi. Peut-être pas très efficace cependant. –

+1

Ne pas référencer dans une portée globale. Enveloppez le code dans une fonction ou utilisez 'BenchmarkTools' et' @btime getindex. ($ Out, 1) 'à la place. – tim