How to implement this function in a single line in MATLAB - matlab

The resulting indices of the transformed light field data are ub, vb, sb, tb. Each of them is depending on variables u,v,s,t.
Sorry for being unclear, let me mention that I am trying to transform a 4D dataset through some sort of matrix. In the code below M is simply a 3D transformation matrix.
f=0.1;
n = 11;
[u,v,s,t] = ndgrid([1:Size(3)],[1:Size(4)],[1:Size(1)],[1:Size(2)]);
alpha = M(3,1)*s+M(3,2)*t+M(3,3)*nf;
beta1 = M(1,1)*u+M(1,2)*v+M(1,4);
beta2 = M(2,1)*u+M(2,2)*v+M(2,4);
C = M(3,1)*u+M(3,2)*v+M(3,4);
D1 = M(1,1)*s+M(1,2)*t+M(1,3)*nf;
D2 = M(2,1)*s+M(2,2)*t+M(2,3)*nf;
ub = -D1.*C./alpha+beta1;
vb = -D2.*C./alpha+beta2;
sb = nf*D1./alpha;
tb = nf*D2./alpha;
for s = 1:Size(1)
for t = 1:Size(2)
for u = 1:Size(3)
for v = 1:Size(4)
newLF(sb(u,v,s,t),tb(u,v,s,t),ub(u,v,s,t),vb(u,v,s,t)) = LF2(s,t,u,v);
end;
end;
end;
end;
Now since ub,vb,sb and tb are depending on u,v,s,t therefore, it is not possible to assign it like newLF = LF2;
Now the question is how to minimize these for loops to a single line.

The answer is
newLF = LF2;
Meaning, that code does nothing but copy LF2 to newLF.
To check that I'm right, just let the code run with some random matrix LF2 and then evaluate
all(newLF(:) == LF2(:))
and you'll find it always evaluates to "true".
First of all, your use of sb, tb, ub, vb is redundant. You are indexing into a grid, but this just reproduces the indices. The line
newLF(sb(u,v,s,t),tb(u,v,s,t),ub(u,v,s,t),vb(u,v,s,t)) = LF2(s,t,u,v);
is equivalent to the line
newLF(s,t,u,v) = LF2(s,t,u,v);
This of course is just element-wise copying.
The impression of permutation noted by Shai is given by the line
[ub,vb,sb,tb] = ndgrid([1:Size(3)],[1:Size(4)],[1:Size(1)],[1:Size(2)]);
which looks like you are preparing to permute dimensions (1, 2) with dimensions (3,4). However, you use this index grid in the form sb, tb, ub, vb, assigning the value from s, t, u, v, so the permutation is not actually performed.
Assuming you actually do want to do that permutation of dimensions, the correct code would be
for s = 1:Size(1)
for t = 1:Size(2)
for u = 1:Size(3)
for v = 1:Size(4)
newLF(u,v,s,t) = LF2(s,t,u,v);
end;
end;
end;
end;
In this case Shai would be right, the corresponding one-liner is
newLF = permute(LF2, [3 4 1 2]);

Related

Is there a more efficient way for performing multiple nested for loops in matlab?

I have a small logical array (A) of size 256x256x256 with an unknown shape of ones somewhere in the array. Also there is a smaller double array (se) of size 13x13x13. In se there is a defined cube of logical ones in the middle of the array (se).
I need to run over every logical element in A and for each logical one in A the smaller array se needs to add its ones to A. Meaning dilating the shape of A by se.
Here is what I got so far. It works, but is of very poor performance in respect to speed.
Does anyone has a suggestion of how to speed up this coding task?
[p, q, r] = size(se);
[m, n, o] = size(A);
temp = zeros(m, n, o);
for i = 1:m
for j = 1:n
for k = 1:o
if img_g(i, j, k) == 1
for s = 1:p
for t = 1:q
for u = 1:r
if se(s, t, u) == 1
c = i + s;
d = j + t;
e = k + u;
temp(c, d, e) = 1;
end
end
end
end
end
end
end
end
B = temp;
I am very grateful for any help and suggestions that improve my programming skills.
dependent on the processor you're using, you can at least use "parfor" for the outer loop (first loop).
this enables parallel computing and accelerates your performance by the number of physical kernels your processor got.
I'm not 100% sure this does what you're asking (as I'm not completely clear on what your code does), but perhaps the methodology will give some inspiration.
I've not generated a "logical" A, but a random one, and I've set a cube inside equal to 1. Similar for se. I use meshgrid to get arrays corresponding to the indices, and use a mask of logical indexing. (perhaps my mask is what you have for A in the first place?)
A = rand(255,255,255);
A(40:50, 23:33, 80:100) = 1;
mask = (A==1);
[I,J,K] = meshgrid(1:255);
se = rand(13,13,13);
se(4:6, 3:7, 2:8) = 1;
se_mask = (se==1);
[se_I, se_J, se_K] = meshgrid(1:13);
Here I'm assuming that the cube in A is far enough from any edge (say 13 spaces) so we wont get c, d or e larger than 255.
I've flattened mask into a row vector so find gives a single index ii we can use to refer to any point in A, then the original i,j and k indices are in I(ii), J(ii), and K(ii) respectively. Similar for se_I etc.
temp = zeros(255, 255, 255);
for ii=find(mask(:).')
for jj=find(se_mask(:).')
c = I(ii) + se_I(jj);
d = J(ii) + se_J(jj);
e = K(ii) + se_K(jj);
temp(c,d,e) = 1;
end % for
end % for
The matrices I, J, K, se_I, se_J and se_K are regular, so if making/storing these becomes a bottleneck you can write functions to replace them. Matrix temp might be very sparse depending on the size of your cubes of ones, so you could look into using sparse.
I've not compared the timings against your solution.

Sweeping initial conditions for a set of ODEs using parfor

I am currently trying to use parfor to sweep across a range of initial conditions for a set of differential equations solved by ode45. The code works fine using two nested for loops but I was hoping parfor could make the process more efficient. Unfortunately, I have run into an issue where the solver is able to solve one of the combinations in the matrix representing initial conditions across a range of variables, but the others seem to have their initial values all set at 0, instead of the values specified by the initial conditions. It may have something to do with the fact that I need to create a matrix of zeros ('P') that the results will be written into, perhaps overwriting the initial conditions(?) Any help would be greatly appreciated.
Thanks,
Kyle
function help(C, R)
A = 0.01;
B = 0.00;
C = [0.001,0.01];
D = 0.00;
R = [1e-10,1e-9];
[CGrid,RGrid] = meshgrid(C,R);
parfor ij = 1 : numel(CGrid)
c2 = [A; B; CGrid(ij); D; RGrid(ij)];
[t,c] = ode45('ode_sys',[0:1:300],c2);
for k=1:length([0:1:300])
for l=1:length(c2)
if c(k,l)<0
c(k,l)=0;
end
end
end
P = zeros(301,5,numel(R),numel(C));
temp = zeros(301,5);
temp(:,1) = c(:,1);
temp(:,2) = c(:,2);
temp(:,3) = c(:,3);
temp(:,4) = c(:,4);
temp(:,5) = c(:,5);
P(:,:,ij)=temp;
parsave('data.mat', P);
end
end
You have one error, and a few opportunities to simplify the code.
In the parfor loop, you have this line P = zeros(301,5,numel(R),numel(C)); which overwrites P with all zeros at each iteration. Put this before the parfor loop.
The first double-for loop that makes negative elements of c zero can be done using max(c,0), which should be more efficient. You can also do P(:,:,ij)=c(:,1:5) directly.
So you can replace your parfor loop with
P = zeros(301,5,numel(R),numel(C));
for ij = 1 : numel(CGrid)
c2 = [A; B; CGrid(ij); D; RGrid(ij)];
[t,c] = ode45('ode_sys',0:300,c2);
c = max(c,0);
P(:,:,ij) = c(:,1:5);
parsave('data.mat',P);
end

Attempted to access b(1,2); index out of bounds because size(b)=[3,1]

I have a uni assignment to create a very basic function that works the same as the backslash command in MATLAB. I'm not looking for the answer to the uni, my intentions are not to cheat, I'm just stuck on a problem and need guidance on how to get this to work.
So I think I'm close to the answer.
function x = matrix_solve(A,b)
invA=inv(A);
[m,n] = size(A); % m is num rows, n is num of columns
nb = size(b,1);
if m == n && nb == m
x = zeros(m,n);
for i = 1:m
for j = 1:n
x(1,j) = x(1,j)+ invA(i,1)*b(1,j);
end
end
else
error('Error')
end
Using a basic square matrix
b = [1;3;2]
A = [3,1,2;3,2,1;3,3,3]
I keep getting the error mentioned in the title.
I'm pretty familiar with other code but I'm very very new to Matlab.
The cause of the index out of bound error is you're trying to access an element that doesn't exist at this line
x(1,j) = x(1,j)+ invA(i,1)*b(1,j);
Instead it should be
x(1,j) = x(1,j)+ invA(i,1)*b(j,1);
I.e. just change b(1,j) to b(j,1). bis a column vector of size 3 (size(b)=[3,1]) and you are trying to access an element at row 1, column 2, but there is only 1 column.

Matlab: Building a molecular library through permutation [duplicate]

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 8 years ago.
I am trying to make an index all possible molecules with 0-46 Hydrogen, 0-20 carbon, 0-13 oxygen, etc. I have 7 atoms in which I am interested: H, C, O, N, Cl, F, and S. I have written the following for loop to show what I am trying to achieve:
MassListIndex = []
%MassIndex = [h,c,o,n,cl,f,s]
for h = 0:46;
for c = 0:20;
for o = 0:13;
for n = 0:15;
for cl=0:5;
for f=0:5;
for s=0:5;
MassListIndex = [MassListIndex;[h,c,o,n,cl,f,s]];
end;
end;
end;
end;
end;
end;
end;
This strikes me as terribly inefficient; I don't want to wait around for 2 months for this to run. I have tried using the combinator.m script, but the problem is that there is only one input for the length of the set that is 'permutated' ie if I want to have up to 46 hydrogens, I need to also have 46 of each of the other 6 atoms. This is computationally...heavy (46^7 ~= 436 billion).
Is there any way to make this sort of computation more efficient? Or do I need to think more about shrinking my list by riding it of 'nonsense permutations' (As far as I know, the molecule H40C2 has never been observed!)
Thanks
The first problem is not that hard. At least not if you remember to preallocate!
I changed you the code into this:
mxidx = 47*21*14*16*6*6*6;
MassListIndex = zeros(mxidx,7);
idx = 1;
for h = 0:46;
for c = 0:20;
for o = 0:13;
for n = 0:15;
for cl=0:5;
for f=0:5;
for s=0:5;
MassListIndex(idx,:) = [h,c,o,n,cl,f,s];
idx = idx + 1;
end;
end;
end;
end;
end;
end;
end;
And it ran in less than a minute on my computer.
Usually Matlab will warn you if you forget to preallocate; and whenever you (like in this case) know in advance the size of you matrix, you should preallocate!
The other problem on the other hand, 47^7 = 506623120463 (more than 500 billions - it is 47^7 instead of 46^7 since the list 0:46 has 47 elements). So even if you only use one byte pr. row in you matrix (which you certainly don't) it will still take up more that a half terabyte! And the calculation times will likewise be humongous!
But really when would you ever need this list. The way you have constructed your list you can easily calculate an entry just by the index eg.:
function m = MassListIndex(a,b)
a = a - 1;
lst = zeros(1,7);
for i = 1:7
lst(8-i) = mod(a,47);
a = floor(a /47);
end
if nargin < 2
m = lst;
else
m = lst(b);
end
end
Edit:
If you want it to also calculate the mass, you may do something like:
function mass = getMassFromPermutationNumber(a)
a = a - 1;
lst = zeros(1,7);
for i = 1:7
lst(8-i) = mod(a,47);
a = floor(a /47);
end
mass = lst*[1.00794;12.011;15.9994;20.1797;35.4527;18.9984;32.066];
end
Source for masses: http://environmentalchemistry.com/yogi/periodic/mass.html
Disclaimer: I'm not that good at chemistry, so please apply reasonable amounts of skepticism!

Compute the convolution of two arrays in MATLAB

I am trying to generate an array from some starting values using this formula in MATLAB:
yt = a0 + ∑i=1p (ai ⋅ yt-i), t ≥ p
p is some small number compared to T (max t). I have been able to make this using two for cycles but it is really slow. Is there some easy way to do it?
First p values of y are provided and vector a (its length is p+1) is provided too...
This is what I have so far, but now when I tried it, it doesn't work 100% (I think it's because of indexing from 1 in MATLAB):
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end
EDIT: I solved it, I am just not used to Matlab indexing from 1...
This statement
if(p>=t)
looks odd inside a loop whose index expression is
for t = p+1:T+1
which seems to guarantee that t>p for the entire duration of the loop. Is that what you meant to write ?
EDIT in response to comment
Inside a loop indexed with this statement
for j = 2:p
how does the reference you make to a(j) ever call for a(0) ?
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end