2015-11-18 2 views
-1

Étant donnéY at-il quelque chose comme arrayfun, mais pour plusieurs dimensions?

X = [x0,x1,...,xN]; 
Y = [y0,y1,...,yM]; 
function result = f(x, y) 
    ... % Cannot use broadcasting. Must take values. Returns a value. 
end 

Je veux obtenir une matrice

f(x0,y0) f(x0,y1) ... f(x0,yM) 
f(x1,y0) f(x1,y1) ... f(x1,yM) 
...  ...  ... ... 
f(xN,y0) f(xN,y1) ... f(xN,yN) 

Je sais que je peux utiliser deux boucles imbriquées for, mais est-il quelque chose qui pourrait paralléliser cela? Quelque chose avec l'interface semblable à arrayfun?


Pour les curieux f fonction:

X = [some vector] 
W = [some vector] 
p(w) % returns a real number; for given vector, returns a vector 
g(x, w) % returns value from X; can use broadcasting just like (x .* w). 

function result = f(x, y)     % takes 2 values from X 
    result = sum(p(W(g(x,W) == y))); 
    %     |   |  - boolean vector 
    %    |    |  - vector of some values from W 
    %    |     | - vector of some real values 
    %  |       | - a single value 
end 
+1

[ 'this'] (http: //stackoverflow.com/questions/12522888/arrayfun-peut- être-significantly-slower-than-an-explicit-loop-in-matlab-why) pourrait valoir le détour. Pourriez-vous partager l'implémentation de la fonction 'f'? – Divakar

+0

'arrayfun' n'est pas parallélisé, c'est juste une autre façon d'écrire une itération. Au moins dans les versions matlab récentes, je m'attends à ce qu'une boucle imbriquée soit aussi rapide que n'importe quelle autre solution. Sauf si vous l'avez fait en utilisant la radiodiffusion. – Daniel

+1

FYI 'arrayfun' peut prendre plusieurs arguments:' arrayfun (@ (x, y) f (x, y), X, Y) ' – Geoff

Répondre

1

@ réponse de Matt semble plus agréable que cela, mais il est faisable sans aucun doute avec arrayfun le désagrément mineur d'utiliser meshgrid et ' pour formater les entrées et sorties:

X  = rand(10,1); 
Y  = rand(5,1); 
f  = @(a,b) a+b; 
[xx,yy] = meshgrid(X,Y); 
out  = arrayfun(@(a,b) f(a,b),xx,yy)'; 
+0

Je ne savais pas que la balise MATLAB avait été retirée avant de poster ma solution - si cette solution n'est pas valide OCTAVE Je vais le supprimer. – Geoff

+0

Ne le supprimez pas! Cela fonctionne très bien!Merci :) (petit tweak: avec 'ndgrid' aucune transposition n'est requise) – etam1024

+0

Bien qu'il soit toujours séquentiel et ait la même vitesse que les boucles imbriquées, mais au moins mon code est beaucoup plus propre. – etam1024

0

Quelque chose comme cela devrait fonctionner.

f = @(a,b) a + b; 
    x = (0:10)'; 
    y = -5:1; 
    res = bsxfun(f, x, y); 

res = 

-5 -4 -3 -2 -1  0  1 
-4 -3 -2 -1  0  1  2 
-3 -2 -1  0  1  2  3 
-2 -1  0  1  2  3  4 
-1  0  1  2  3  4  5 
0  1  2  3  4  5  6 
1  2  3  4  5  6  7 
2  3  4  5  6  7  8 
3  4  5  6  7  8  9 
4  5  6  7  8  9 10 
5  6  7  8  9 10 11 

La clé de bsxfun travail organise vos facteurs de production tels qu'ils s'élargis correctement. Utilisez doc bsxfun pour voir ce dont vous avez besoin en termes de dimensions non-singleton pour obtenir la sortie que vous voulez.

Bien sûr, ma sortie est transposée à partir de la demande d'origine, mais elle est facilement résolue avec res = res';.

+0

La documentation d'Octave indique "La fonction F doit être capable d'accepter deux arguments de vecteur de colonne de longueur égale, ou un argument de vecteur de colonne et un scalaire.". Comme je l'ai écrit, ma fonction doit prendre deux valeurs. – etam1024

+0

@ etam1024 alors vous devez supprimer la balise 'matlab' de votre question. Parce que ça fonctionne bien dans Matlab. Clairement mon exemple montre 2 vecteurs de longueur différente. – Matt

+0

Mais la documentation Matlab sur 'bsxfun' dit aussi que la fonction doit accepter les vecteurs comme arguments (je ne vais pas le coller ici, car c'est assez long). Modifiez votre fonction 'f' pour qu'elle affiche les arguments passés et indique ce que vous obtenez. – etam1024