Suppose I want to evaluate a function of three variables over a grid of points in 3D space.
For example, using three nested loops
x = 1:2; y = 10:11; z = 100:102;
a(ii,jj,kk) = f(x(ii),y(jj),z(kk));
However, I'd rather use a single @doc:parfor loop.
One approach is to @doc:ndgrid the inputs, then reshape to rows, evaluate, and reshape the result. Or, preallocate because we know the size and ordering of the output and use linear indexing
aa(ii) = f(c(ii,1),c(ii,2),c(ii,3));
The "modern" approach avoids forming the temporary variables X,Y, and Z and instead uses @doc:combinations and then iterate over the rows. I could try the same approach as above, but I can't find a deifnitive statement on ordering of the output of combinations(), so don't know the dimensions needed for preallocation. Instead, preallocate and fill in a 1D vector for starters
aaa(ii) = f(c{ii,1},c{ii,2},c{ii,3});
Now i want to @doc:reshape aaa back to the same shape as the underlying 3D grid, which would be most naturally represented in @doc:ndgrid form, so I can index into the reshaped aaa to extract the values of the function.
The first questions are: what is the ordering of the rows of c, and is that ordering guaranteed to be the same for all calls to combinations()? As far as I can tell, doc@combinations is silent on these issues.
For this particular problem, the rows of c are ordered in reverse ndgrid
[X(:),Y(:),Z(:)],table2array(combinations(x,y,z))
ans =
1 10 100
1 10 101
1 10 102
1 11 100
1 11 101
1 11 102
2 10 100
2 10 101
2 10 102
2 11 100
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans =
1 10 100
1 10 101
1 10 102
1 11 100
1 11 101
1 11 102
2 10 100
2 10 101
2 10 102
2 11 100
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Now I need to @doc:permute after the reshape to recover the function in the desired form, which is a bit counterintuitive (and I shouldn't have had to experimentally determine the ordering of c to figure it out)
aaa = permute(reshape(aaa,size(X)),ndims(X):-1:1);
Suppose aaa is a very large array. Does that call to permute incur a lot of additional overhead?
I suppose that if I knew a priori how combinations() ordered it's output I could preallocate to the correct size, fill in with linear indexing, and then there would be no need to reshape. But I don't see an easy way to get around the need to permute.
1. Is the ordering of the output rows from combinations documented?
2. Will the ordering be the same on every call to combinations?
3. Is the ordering shown for this problem sensible? Frankly, I was quite surprised; I was expecting the ordering to be consistent with ndgrid(x,y,z). I wonder what led to this design choice.
These questions apply regardless of the data types of the inputs to combinations() and the output of f(); numeric just shown here for simplicity.