-1

Given

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

I want to get a matrix

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)

I know I can just use two nested for loops, but is there something that could parallelize this? Something with interface similar to arrayfun?


For those curious about f function:

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
Matt
  • 2,554
  • 2
  • 24
  • 45
etam1024
  • 843
  • 1
  • 7
  • 17
  • 1
    [`This`](http://stackoverflow.com/questions/12522888/arrayfun-can-be-significantly-slower-than-an-explicit-loop-in-matlab-why) might be worth a look. Could you share the implementation of function `f`? – Divakar Nov 18 '15 at 18:23
  • `arrayfun` does not parallelize, it is just another way to write an iteration. At least in recent matlab versions I expect a nested loop to be at lest as fast as any other solution. Unless you get it done using broadcasting. – Daniel Nov 18 '15 at 18:30
  • 1
    FYI `arrayfun` can take multiple arguments: `arrayfun(@(x,y) f(x,y), X,Y)` – Geoff Nov 18 '15 at 18:35
  • @Geoff yes, but inputs must be vectors of the same size and it produces a vector of `f(x0,y0) f(x1,y1) ... f(xN,yN)`. Totally different thing. – etam1024 Nov 18 '15 at 18:48
  • So, `g(x,w)` is `(x .* w)`? `g` is a function, right? – Divakar Nov 18 '15 at 18:50
  • @Divakar it has some additional multiplications with scalars and they are OK with accepting vectors. You can assume it's just `(x .* w)`. – etam1024 Nov 18 '15 at 19:00

2 Answers2

2

@Matt's answer looks nicer than this, but it's definitely do-able with arrayfun with the minor annoyance of using meshgrid and ' to format the inputs and output:

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)';
Geoff
  • 1,202
  • 10
  • 18
  • I didn't realize the MATLAB tag was removed before posting my solution -- if this solution is invalid for OCTAVE I will delete it. – Geoff Nov 18 '15 at 21:11
  • Don't delete it! It works great! Thanks :) (minor tweak: with `ndgrid` no transposing is required) – etam1024 Nov 18 '15 at 22:30
  • Although it's still sequential and has the same speed as nested loops, but at least my code got much cleaner. – etam1024 Nov 19 '15 at 07:41
0

Something like this should work.

   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

The key to making bsxfun work is arranging your inputs such that they get expanded correctly. Use doc bsxfun to see what you need in terms of non-singleton dimensions to get the output you want.

Of course my output is transposed from the original request but that is easily solved with res = res';.

Matt
  • 2,554
  • 2
  • 24
  • 45
  • Octave documentation says "The function F must be capable of accepting two column-vector arguments of equal length, or one column vector argument and a scalar.". As I wrote, my function must take two values. – etam1024 Nov 18 '15 at 18:53
  • @etam1024 then you need to remove `matlab` tag from your question. Because it works fine in Matlab. Clearly my example shows 2 vectors of different length. – Matt Nov 18 '15 at 19:49
  • But Matlab documentation on `bsxfun` also says that the function must accept vectors as arguments (I won't paste it here, because it's quite long). Modify your `f` function so that it displays passed arguments and tell what you get. – etam1024 Nov 18 '15 at 20:13
  • @etam1024 http://www.mathworks.com/help/matlab/ref/bsxfun.html I don't know what documentation you're reading but it's not from MathWorks. – Matt Nov 18 '15 at 20:40
  • "A binary element-wise function of the form C = fun(A,B) accepts arrays A and B of arbitrary, but equal size and returns output of the same size. [...] fun must also support scalar expansion, such that if A or B is a scalar, C is the result of applying the scalar to every element in the other input array" – etam1024 Nov 18 '15 at 22:11