2

Is there a more efficient way of evaluating a function of two variables on a rectangular grid the the following nested Do loops?

fonGrid[x_, y_, f_] := Module[{n, m, fvals},
  (* x is an n-by-1 vector *) 
  (* y is an n-by-1 vector *) 
  (* f is a scalar function of two variables *)
  (* fvals is an m-by-
  n matirx where fVals[[i,j]]=f[ x[[j]], y[[i]] ] *)
  n = Length[x];
  m = Length[y];
  fvals = Table[0, {m}, {n}]; (* preallocate fvals *)
  Do[ 
   Do[ 
     fvals[[i, j]] = f[x[[j]], y[[i]]];,
     {i, 1, m}];,
   {j, 1, n}];
  fvals] 
Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Ed Hall
  • 51
  • 1
  • 3
  • Welcome to Mathematica.SE! Please edit your question and format the code as a 'code block' for readability. Use the (?) button at the top right corner of the editor for formatting help. – Szabolcs Mar 06 '14 at 23:57
  • 1
    Also note the differences between vectors and matrices in Mathematica. The way you wrote this code suggests to me that you are used to MATLAB. MATLAB doesn't support vectors at all, only matrices. You can have 1 by n or n by 1 "row vector" or "column vectors". Don't use these in Mathematica. Use true one-dimensional vectors such as {1,2,3} instead of a matrix such as {{1,2,3}} or {{1},{2},{3}}. – Szabolcs Mar 07 '14 at 00:02
  • p.s. special case: Array[f, {4, 3}] – Kuba Mar 07 '14 at 00:07

1 Answers1

2

Generally, for good performance, avoid Do loops in favour of Table and functional constructs.

In this case there's a simpler way than Table:

Outer[f, x, y]

Outer is a generalization of the outer product (or Kronecker product) in that it gives you the freedom to choose the operation used in place of the multiplication.

Example:

Outer[f, Range[3], Range[5]]

{{f[1, 1], f[1, 2], f[1, 3], f[1, 4], f[1, 5]}, 
 {f[2, 1], f[2, 2], f[2, 3], f[2, 4], f[2, 5]},
 {f[3, 1], f[3, 2], f[3, 3], f[3, 4], f[3, 5]}}

If you wanted to use Table for some reason, you could directly use

Table[f[a,b], {a, x}, {b, y}]

where x and y are vectors and a and b are iterators that take elements from the vector one-by-one. I recommend that as a beginner you get familiar with Table first. It's a very commonly used and very general function that'll be useful in many cases.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • Latter does not produce results same as OP, you need e.g.fonGrid2[x_, y_, f_] := Table[f[a, b], {b, y}, {a, x}] – ciao Mar 07 '14 at 00:11
  • @rasher Neither does the Outer-version I posted, but I wrote it this way on purpose (instead of transposing). I believe the OP wrote his function this way because he is used to MATLAB which encourages column-major thinking, while Mathematica encourages row-major thinking. In Mathematica a matrix is a list of rows, not a list of columns, so it's typically (not always) more advantageous to work with rows. – Szabolcs Mar 07 '14 at 00:15
  • Of course, I'm just a stickler for giving OPs what they want, even if goofy, and the noting it as such. – ciao Mar 07 '14 at 00:19