I have a code and it works for 3 dimensions, but I want to be able to specify the number of dimensions dynamically. There is a function nchoosek, but it creates an array of non-repeating elements.
This is my code for 3D:
energy_band=70;
count=1;
for i=-energy_band:energy_band
for j=-energy_band:energy_band
for z=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
out(3,count)=z;
count=count+1;
end
end
end
We need an analogue of this algorithm, but for an arbitrary number of dimensions. For example, when I need to create an array for 4 dimensions, the code will look like this:
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
for j=-energy_band:energy_band
for z=-energy_band:energy_band
for k=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
out(3,count)=z;
out(4,count)=k;
count=count+1;
end
end
end
end
At the moment I am solving this problem with the following function, but as you can see there is no universality here:
function out=energy_array(matrix_version,energy_band)
count=1;
switch matrix_version
case 1
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
out(1,count)=i;
count=count+1;
end
case 2
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
for j=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
count=count+1;
end
end
case 3
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
for j=-energy_band:energy_band
for z=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
out(3,count)=z;
count=count+1;
end
end
end
case 4
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
for j=-energy_band:energy_band
for z=-energy_band:energy_band
for k=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
out(3,count)=z;
out(4,count)=k;
count=count+1;
end
end
end
end
case 5
for i=-energy_band:energy_band %array formation cycle with energy shifts in the range from -1.75 eV to 1.75 eV
for j=-energy_band:energy_band
for z=-energy_band:energy_band
for k=-energy_band:energy_band
for l=-energy_band:energy_band
out(1,count)=i;
out(2,count)=j;
out(3,count)=z;
out(4,count)=k;
out(5,count)=l;
count=count+1;
end
end
end
end
end
end
How can I implement this more elegantly, without spelling out all the different cases?
You can create such arrays using ndgrid. This function outputs a separate array for each column of your desired array, so we need to apply some tricks to collect the arbitrary number of outputs and concatenate them as the columns of a matrix:
function out = energy_array(matrix_version, energy_band)
arrays = cell(matrix_version,1);
range = -energy_band:energy_band;
inputs = repmat({range}, matrix_version, 1);
[arrays{:}] = ndgrid(inputs{:});
arrays = cellfun(@(x) x(:).', arrays, 'UniformOutput', false);
out = cat(2, arrays{:});
end
arrays is a cell array with the number of outputs ndgrid will produce. This is the trick to receive a variable number of output arguments.
inputs is a cell array with the input arguments to ndgrid. inputs{:} is a comma-separated list of the values in the cell array, meaning each element is a separate argument.
arrays contains, after the call to ndgrid, a set of matrix_version arrays, each with matrix_version dimensions. We need to make these into column vectors, which you can do with arrays{i} = arrays{i}(:) for each i. This is what the cellfun line does. Finally, we concatenate the resulting arrays into a single matrix.
[Note: this is a better solution, I'm keeping this one around to prevent deletion.]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With