Mark values from loop for each iteration - matlab

I want to mark each value that comes out of my loop with a value.
Say I have a variable number of values that come out of each iteration. I want those values to be labeled by which iteration they came out of.
like
1-1,
2-1,
3-1,
1-2,
2-2,
3-2,
4-2,
etc.
where the first number is the value from the loop and the second is counting which iteration it came from.
I feel like there is a way I just cant find it.
ok so here is some code.
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
I want to mark each local value with the iteration it came from for the i:NN. PL is a vector and the output is a set of vectors for each iteration.

For this sort of quick problem I like to create a cell array:
for k = 1:12
results{k} = complicated_function(...);
end
If the output is really complicated, then I return a struct with fields relating to the outputs:
for k = 1:12
results{k}.file = get_filename(...);
results{k}.result = ...;
end

Currently as it is right now, in your inner 1:NN loop, your local(c) variable is being updated or overwritten. You never apply the previous value of local, so it is not some iterative optimization algorithm(?)...
Perhaps an easy solution is to change the size/type of local from a vector to a matrix. Let's say that local is of size [npoints 1]. Instead you make it of size [npoints NN]. It is now a 2d-array (a matrix of npoints rows and NN columns). use the second dimension to store each (assumed column) vector from the inner loop:
local = zeros([npoints NN]);
%# ... code in bewteen ...
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c, i)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c, i)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
end
The c'th row of your local matrix will then corresponds to the NN values from the inner loop. Please note that I have assumed your vector to be a column vector - if not, just change the order of the sizes.

Related

How to avoid sub2ind and decrease execution time in manipulating multidimensional arrays using original indexes

I would like your suggestions to make my code faster (and elegant). In particular, sub2ind (and the if-loop) slow it down dramatically according to the matlab profiler. I will try to explain what I need from my code as simply as I can.
Assuming I have the following problem, for simplicity.
Every citizen of every city has a car of a specific brand and a specific color.
What I would like to have is a 4D multidimensional array Data_4D(City,Citizen,Car_brand,Car_color) that I can manipulate (read and modify) using as indexes only these four dimensions.
Then, I want to reshape my multidimensional array into a 1D array Data_1D with
length(Data_1D)=(City*Citizen*Car_brand*Car_color)
The order of the elements must follow an indexing rule:
Example assuming City=2, Citizen=2, Car_brand=2, Car_color=2;
Data_1D(1)=Data_4D(1,1,1,1)
Data_1D(2)=Data_4D(1,1,1,2)
Data_1D(3)=Data_4D(1,1,2,1)
Data_1D(4)=Data_4D(1,1,2,2)
Data_1D(5)=Data_4D(1,2,1,1)
Data_1D(6)=Data_4D(1,2,1,2)
Data_1D(7)=Data_4D(1,2,2,1)
Data_1D(8)=Data_4D(1,2,2,2)
Data_1D(9)=Data_4D(2,1,1,1)
Data_1D(10)=Data_4D(2,1,1,2)
Data_1D(11)=Data_4D(2,1,2,1)
Data_1D(12)=Data_4D(2,1,2,2)
Data_1D(13)=Data_4D(2,2,1,1)
Data_1D(14)=Data_4D(2,2,1,2)
Data_1D(15)=Data_4D(2,2,2,1)
Data_1D(16)=Data_4D(2,2,2,2)
After that I will get this 1D array, shaped as above, I need to create a matrix Matrix_Final( NRows,length(Data_1D)) in which every row is an array Data_1D. In every row NRows, the array Data_1D will have the same amount of elements but with different values.
The amount of rows depends also on some (or all) of the four the dimensions City,Citizen,Car_brand,Car_color (respecting the same indexing rule as for Data_1D) and the array built in each line must be manipulated according also to the value of the matrix row (by using the four indexes, which is the common rule for both NRows and Data_1D).
Example:
Assuming City=2, Citizen=2, Car_brand=2, Car_color=2;
Assuming NRows depends on all the four dimensions.
I will have Matrix_Final( length(DATA_1D), length(DATA_1D)).
I want that all the data of my array DATA_1D are zeros, except one element, which has to be the element that has the same indexes values(City,Citizen,Car_brand,Car_color) as NRows(City,Citizen,Car_brand,Car_color)
So at the row NRows(1), only Data_1D(1) is non-zero. For this example, the result is an eye matrix.
clc
clear all
%Dimensions Definition
City=2;
Citizen=2;
Car_brand=2;
Car_color=2;
%Length of Data
Length_Data_1D=City*Citizen*Car_brand*Car_color;
%preallocation Matrix_Final
Matrix_Final=zeros(City*Citizen*Car_brand*Car_color, Length_Data_1D);
%indexes of the dimensions
indexes_array_carcolor=repmat(repelem([1:Car_color], 1), [1 City*Citizen*Car_brand]);
indexes_array_carbrand=repmat(repelem([1:Car_brand], Car_color), [1 City*Citizen]);
indexes_array_citizen=repmat(repelem([1:Citizen],Car_brand*Car_color),[1 City]);
indexes_array_city=repmat(repelem([1:City],Citizen*Car_brand*Car_color),[1 1]);
%Initializing loop variable
column_Matrix_final=1;
for CITY_selected=1:City
for CITIZEN_selected=1:Citizen
for CAR_BRAND_selected=1:Car_brand
for CAR_COLOR_selected=1:Car_color
%Data_4D Construction
Data_4D=zeros(City,Citizen,Car_brand,Car_color);
for city=1:length(indexes_array_city)
for citizen=1:length(indexes_array_citizen)
for car_brand=1:length(indexes_array_carbrand)
for car_color=1:length(indexes_array_carcolor)
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(sub2ind(size(Data_4D),indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color)))=1;
end
end
end
end
end
%Data_4D transformation into array Data_1D
Data_1D=zeros(1,City*Citizen*Car_brand*Car_color);
tic=1;
for city=1:City
for citizen=1:Citizen
for car_brand=1:Car_brand
for car_color=1:Car_color
Data_1D(tic)=Data_4D(city,citizen,car_brand,car_color);
tic=tic+1;
end
end
end
end
%Adding Data_1D to the next for of Matrix_Final
Matrix_Final(column_Matrix_final,:)=Data_1D;
column_Matrix_final=column_Matrix_final+1;
%Display of the four most external loops indexes to show code
%advancement
CAR_COLOR_selected
end
CAR_BRAND_selected
end
CITIZEN_selected
end
CITY_selected
end
spy(Matrix_Final)
If you add e.g.
&& indexes_array_carcolor(car_color)==2
in the if loop, only the elements of Data_1D(City,Citizen,Car_brand,Car_color=2) in NRows(City,Citizen,Car_brand,Car_color=2) will be non-zero.
I would like to know if there are faster ways to set up the problem, but keeping the same ability to manipulate Data_1D an Matrix_Final using the four indexes (City,Citizen,Car_brand,Car_color) and the ability to correlate NRows and the elements of Data_1D using these four indexes.
Thank you for your help!
This is how you have coded it
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(sub2ind(size(Data_4D),indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color)))=1;
end
Another way 1
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color))=1;
end
Another way 2
Data_4D(indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color))=double((indexes_array_city(city)==CITY_selected)& ...
(indexes_array_citizen(citizen)==CITIZEN_selected)& ...
(indexes_array_carbrand(car_brand)==CAR_BRAND_selected)& ...
(indexes_array_carcolor(car_color)==CAR_COLOR_selected));
All three of them will yield same result. Try which is faster and use it.
%% Data_4D transformation into array Data_1D
Data_4D_size=size(Data_4D);
Data_1D_size=prod(Data_4D_size);
temp = permute(Data_4D, [4 3 2 1]);
Data_1D=reshape(temp,Data_1D_size,1);
Use this for 4D to 1D convertion
If still need more speed. Compile it to mex. Compiled code runs faster.

Double for loop, how to set non-continuous index?

If I want to construct a double for loop, but for index k I don't want it to be continuous index but like [1,2,4,7]. I tried to do the following, and it did not work.
for i=1:100
for k=1:2:4:7;
b(i)=i*k;
end
end
Anyone could help me deal with that?
When you want to construct an array, you don't want to necessarily use the colon (:) operator unless you want to create a range of values (like you do when you want i to be all values between 1 and 100), instead you want to use square brackets ([]) with comma separators to explicitly create an array of discrete values.
k = [1,2,4,7];
Now that you do this you can specify your loop like you had it with this small substitution for the values of k
kvalues = [1,2,4,7];
for i = 1:100
for k = 1:numel(kvalues)
b(i) = i * kvalues(k);
end
end
Notice that I have defined kvalues once outside of the loop so that it is not created every iteration through the outer loop (thanks to #dfri for pointing this oversight out)
The way that you have your loop written, you're actually over-writing the value of b(i) every time through the inner loop. I'm not sure if that's what you intended to do. If it is, then you can reduce your loop to the following:
b = k(end) * (1:100);
Otherwise, if you meant to have it be b(i,k) = i * k, you could rewrite this with bsxfun.
b = bsxfun(#mtimes, [1,2,4,7], (1:100).');
The syntax k=1:2:4:7 will not work as you intend. Usually we make use of the "two colon" syntax to describe a non-default (1) step size from the given start to end values, k = start:stepSize:end. Using an additional colon here even yields a Matlab warning ("third colon probably not intended?").
One possible workaround is to let your "non-continuous" indices reside in a vector and extract members of this vector in the inner for loop as follows
nonContIndex = [1; 2; 4; 7];
numIndices = numel(nonContIndex);
b = zeros(100,numIndices);
for i=1:100
for k=1:numIndices
b(i,k)=i*nonContIndex(k);
end
end
As noted by comments and the other answer: if b is simply a vector, your original loop will overwrite the b(i):th entry for each run of the inner loop. The above assumes that you in fact want a 2D matrix as a result.

Changing a code to get the Goldbach conjecture

To test the Golbach conjecture I have found the following code, but when I ren it out, this only gives me the number of combinations of primes, but in fact what I was searching for are the primes,I mean the couple of primes such that I get the even number.
Can someone help me to change the below code in matlab to get the couple of primes?
function y=goldbach_partition(n)
if mod(n,2)==0
y=0;
for i=2:floor(n/2)
if isprime(i) & isprime(n-i)
y=y+1;
end;
end;
end;
Thanks a lot in advance :)
That's pretty simple. Create a new array that will store the prime number i (or n-i... can't say for sure) in an array should the value i (and n-i) pass the criterion, then return that array. BTW, you should move your y=0 statement outside of the if statement, because if n is odd, you will never see y being output and you'll get an error.
Something like this:
function [y,pmes]=goldbach_partition(n) %// Change
y = 0; %// Change
pmes = []; %// Change
if mod(n,2)==0
for i=2:floor(n/2)
if isprime(i) & isprime(n-i)
y=y+1;
pmes = [pmes; i n-i]; %// Change
end
end
end
I'm not sure which prime number you're after - if it's i or n-i, so I've added them both. I've also made sure that both primes should they meet the condition be placed in a single row of your matrix. This way, each row will give you when a pair of primes has passed the condition.
Therefore, the above code will not only return the total number of primes, it'll return an array of all of the primes that passed the condition.
You would then call your function this way in MATLAB:
[y,pmes] = goldbach_partition(n);

Modifying Iteration for Multiple Inputs

I am doing an iteration to find the corresponding latitude/longitude at a height (h_intercept). My code works perfectly for a single height value. However, I want to find the lat/long of 79 heights (1x79 matrix) and therefore have an output that is a 3x79 matrix (llh_test). I've tried a for loop but I can't seem to get the results I want. I am probably doing something stupid.
Basically, I need to modify it so it will run with rng_sat, u_sat and h_intercept all being 1x79 matrices. It needs to step through the entire iteration before moving to the next values of rng_sat, u_sat and h_intercept
Also, I want to store all of the llh_test values (3x79 matrix)
rng_sat= sat_look_tcs_pass1(3,1)/2e2;
u_sat=[sat_look_tcs_pass1(1,1)/sat_look_tcs_pass1(3,1);sat_look_tcs_pass1(2,1)/sat_look_tcs_pass1(3,1);sat_look_tcs_pass1(3,1)/sat_look_tcs_pass1(3,1)];
h_intercept=sat_look_pass1_llh(3,1)/2e3;
h_test=0;
rng_test_min=0;
rng_test_max=rng_sat;
err=0.01;
while abs(h_test-h_intercept)>err
rng_test=(rng_test_min+rng_test_max)/2;
tcs_test=u_sat*rng_test;
llh_test=tcs2llhT(tcs_test,station_llh);
h_test=llh_test(3,:);
if h_test>=h_intercept;
rng_test_max=rng_test;
else
rng_test_min=rng_test;
end
end
The easiest thing to do here would be to encapsulate this into a single for loop, and change the way you're accessing the core variables so that you're using the loop index instead. Looking at your code, I'm assuming that sat_look_tcs_pass1 is a 3 x 79 matrix. I'm also going to assume that the output height h_test is a single value because when you're doing h_test = llh_test(3,:), h_test will actually become a vector, as you are trying to get all of the columns for the third row. I'm going to assume that this is a single value, rather than an array.
To modify this code, this actually will take no effort at all, so here's where you need to modify. Anywhere you see %// NEW is where I modified and anything else is your original code:
llh_test = zeros(3,79); %// Preallocate
for k = 1 : 79 %// You have 79 values to go through
rng_sat = sat_look_tcs_pass1(3,k)/2e2; %// NEW Change to k
u_sat = [sat_look_tcs_pass1(1,k)/sat_look_tcs_pass1(3,k); ...
sat_look_tcs_pass1(2,k)/sat_look_tcs_pass1(3,k);...
sat_look_tcs_pass1(3,k)/sat_look_tcs_pass1(3,k)]; %// NEW - Change to k
h_intercept = sat_look_pass1_llh(3,k)/2e3; %// NEW - Change to k
rng_test_min=0;
rng_test_max=rng_sat;
err=0.01;
while abs(h_test-h_intercept) > err
rng_test=(rng_test_min+rng_test_max)/2;
tcs_test=u_sat*rng_test;
llh_test(:,k) = tcs2llhT(tcs_test,station_llh); %// NEW - llh_test is now a matrix
h_test = llh_test(3,k); %// NEW - Changed the way we are accessing llh_test
if h_test >= h_intercept
rng_test_max=rng_test;
else
rng_test_min=rng_test;
end
end
end
Take a look at the general pattern of your code. You essentially are changing all of the points where you were accessing the first column with the kth column. Also, llh_test is a matrix, and so for each iteration in your loop, you want to access the kth column. llh_test should now be a 3 x 79 matrix as per your specifications.
Good luck!

How to add values to already existing ones in a matrix using 'for' loop in MATLAB?

I wrote a piece of code in MATLAB which basically assigns values from matrix 'Ke' (8x8, just constants) to matrix 'KG' which is initially filled with zeros. Numbers of rows and columns to which values should be assigned are given by the array nEN, which varies in another loop but is alway an array of 4 numbers.
KG=[];
for t=1:Nw
for i=1:Nh
eN=Am(t:t+1,i:i+1)
nEN=reshape(eN',1,[])
for i1=1:4
for i2=1:4
KG((2*(nEN(i1))-1),(2*(nEN(i2))-1))=Ke(((2*i1)-1),((2*i2)-1));
KG((2*(nEN(i1))-1),(2*(nEN(i2))))=Ke((2*i1-1),(2*i2));
KG((2*(nEN(i1))),(2*(nEN(i2))-1))=Ke((2*i1),(2*i2-1));
KG((2*(nEN(i1))),(2*(nEN(i2))))=Ke((2*i1),(2*i2));
end
end
end
end
KG
The thing is sometimes nEN can have the same values as those obtained in the previous iteration, and so my loop rewrites the values which have been already present in 'KG', but I want them to be added together instead. How can I do that?? Thanks.
You could accumulate values in KG with:
KG((2*(nEN(i1))-1),(2*(nEN(i2))-1)) = KG((2*(nEN(i1))-1),(2*(nEN(i2))-1)) + Ke(((2*i1)-1),((2*i2)-1));
KG((2*(nEN(i1))-1),(2*(nEN(i2)))) = KG((2*(nEN(i1))-1),(2*(nEN(i2)))) + Ke((2*i1-1),(2*i2));
KG((2*(nEN(i1))),(2*(nEN(i2))-1)) = KG((2*(nEN(i1))),(2*(nEN(i2))-1)) + Ke((2*i1),(2*i2-1));
KG((2*(nEN(i1))),(2*(nEN(i2)))) = KG((2*(nEN(i1))),(2*(nEN(i2)))) + Ke((2*i1),(2*i2));