How to iterate over a changing vector in Matlab, not consecutive number? - matlab

I am really a beginner level at matlab. Now I want to have a loop, such that it iterates over a vector (not consecutive numbers) which contains a decreasing number of elements through iteration.
For example, I have [1; 2 ;3; 4] (thinking of it as person 1, 2, 3, 4)
then I want to do something such that for example person 1 and 4 gets food, person 2 and 3 left with no food.
In the next round, I want person 2 and 3 (those unassigned)to go through the assignment process again but not 1 and 4.
So I create a vector [2;3] to keep track of those left without food.
However,the for i=1:length(vector) gives me a series of consecutive numbers, what I want is
for i in vector do something; end
How to implement this?
when I just put
i=vector,
Matlab says Index exceeds matrix dimensions

If you want to loop through an arbitrary vector, just use that vector directly in a for loop. For example:
vector = [3, 4, 7, 1, 1]
for i = vector
disp(i)
end
will output 3 4 7 1 1. This is the equivalent of "for i in vector do something."

for i=1:length(vector) is giving you an index into the vector - it will always be consecutive because it represents the first..last position of the vector.
It sounds like you want to get an identifier out of the vector. You can do this within your existing loop: id=vector[i]

Have you thought about using Matlab structs?
s = struct(field1,value1,...,fieldN,valueN)
You can have an array 'people' of structs (of type person) which you can loop through...
for i=1:length(people)
if people(i).HasBeenFeed = False
% feed this person...
end
end

Related

In MATLAB, how to compare the elements of 2 vectors in the most efficient way?

I have a vector r, which stores the previously taken actions. Let,
r=[8,8,8,2,2,6,6, ... , 4,4,4]; % (8:up, 2:down, 4:left, 6:right)
and I have a second vector actions that indicates the currently available actions. Let,
actions=[2,6,8];
[~,n]=size(actions);
and let n indicate the number of available actions. I want to compare the last n elements of vector r with the elements of vector actions and eliminate the current action that is in the opposite direction i.e. to avoid repetitions.
For example, since in this case vector r indicates that the last action was towards left, in vector actions 6 should be eliminated and the result would be
actions=[2,8];
What is an efficient (i.e. ideally by avoiding loops) way of achieving this? Thanks.
I would define an array with the oposite actions, that in this case would be
oposite=[0 8 0 6 0 4 0 2]% (8:up, 2:down, 4:left, 6:right)
Then, to remove from actions the ones that have been used in tha last n you just use bsxfun to do singleton expansion of the equal function, so that actions would be:
actions(any(bsxfun(#eq,oposite(actions)',r(end-n+1:end)),2))=[];
That's it, just one line once 'oposite' is defined.
I solved it by defining a matrix that held the opposite action pairs. Then takes the last n- unqiue values of r and removes its pair from the actions array.
pairs = [2 8;...
8 2; ...
4 6; ...
6 4];
r=[8,8,8,2,2,6,6,4,4,4];
actions=[2,6,8];
[~,n]=size(actions);
%The unique last n-values of r
lastN_r = unique(r(end-n+1:end));
%Where these are in the pairs matrix
matchI = ismember(pairs(:,1),lastN_r);
%Remove them.
parsedAct = actions(~ismember(actions,pairs(matchI,2)))
parsedAct =
2 8

Windowed subtraction of vectors that are not same size and then finding the mean of results

Good day,
I have a question what I want to achieve without the loop if possible. As title says I need to do windowed subtraction of vectors that are not same size and then finding the mean of results.
As example, let say that we have vector a = [2 3 4 5 6] and vector b = [1 2].
Program will have to move window with smaller numbers of elements (in this example vector b) over bigger one (vector a) and make operations on that way so it starts in first two elements in vector a and make subtraction with vector b and then sum results and find mean.
In this example it will just make calculation of subtraction 2-1 = 1, 3-2 = 1, summing results 1+1=2 and divide them with 2 (because vector b is that size). Final result is 1.
Then we move window on second elements of vector a (value 3 and 4 there, or index 2 and 3) and repeat process to the last elements of vector a.
For final result we need to get vector c who consist of elements [1 2 3 4] for this example.
Is this possible to do without looping because I have data sets over 10k of size. Thanks in advance
I can solve it with only one loop, iterating through "b" (two loops in your example).
Declare vectors (as columns! This is needed for matlabs computations to work)
a = [2 3 4 5 6]';
b = [1 2]';
Declare matrix for computed results. Each column represents subtractions of elements in "a" with one of the elements in "b".
c = zeros(length(a)-length(b)+1,length(b));
for k = 1:length(b)
c(:,k) = a(k:length(a)-length(b)+k)-b(k);
end
Now just sum the elements in "c" row wise and divide by length of "b" to get the mean
result = sum(c,2)/length(b);
You can simplify this for your exact example, but this is a generic solution for any vetors "a" and "b", where "b" is the smaller vector.

Matlab - Access elements form each column using a vector containing the rows [duplicate]

I'm writing a MATLAB function to read out data into an n-dimensional array (variable dimension size). I need to be able to access a specific point in the Matrix (to write to it or read it, for example), but I don't know ahead of time how many indexes to specify.
Currently I have a current_point vector which I iterate through to specify each index, and a max_points vector which specifies the size of the array. So, if for example I wanted a 3-dimensional array of size 1000-by-15-by-3, max_points = [1000 15 3], and current_point iterates from [1, 1, 1] to [1000, 15, 3] ([1, 1, 1] -> [1000, 1, 1] -> [1, 2, 1] -> [1000, 2, 1] ->...). What I'd like to be able to do is feed current_point as an index to the matrix like so:
output_matrix(current_point) = val
But apparently something like output_matrix([1 2 3]) = val will just set outputmatrix(1:3) = 30. I can't just use dummy variables because sometimes the matrix will need 3 indexes, other times 4, other times 2, etc, so a vector of variable length is really what I need here. Is there a simple way to use a vector as the points in an index?
Using the function sub2ind to create a linear index is the typical solution to this problem, as shown in this closely-related question. You could also compute a linear index yourself instead of calling sub2ind.
However, your case may be simpler than those in the other questions I linked to. If you're only ever indexing a single point with your current_point vector (i.e. it's just an n-element vector of subscripts into your n-dimensional matrix), then you can use a simple solution where you convert current_point to a cell array of subscripts using the function num2cell and use it to create a comma-separated list of indices. For example:
current_point = [1 2 3 ...]; % A 1-by-n array of subscripts
subCell = num2cell(current_point); % A 1-by-n cell array of subscripts
output_matrix(subCell{:}) = val; % Update the matrix point
The operation subCell{:} creates the equivalent of typing subCell{1}, subCell{2}, ..., which is the equivalent of typing current_point(1), current_point(2), ....
I know it is too late but for anybody who will find this topic. the easiest way that work for me is to use: diag(A (x(:),y(:)) );
unfortunately this works only if you need to get values from the matrix, not for changing values
You can use the sub2ind function to get the linear index from the subscript.
Example:
A=magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
selectElement={2,3}; %# get the element at position 2,3 in A.
indx=sub2ind(size(A),selectElement{:});
A(indx)
ans =
10
In the above example, I've stored the subscripts (can be any number of dimensions) as a cell. If you have it stored as a vector, simply use num2cell() to convert it to a cell.
You can now easily assign a value to this as A(indx)=value;. I've used different variables than yours to keep the answer general, but the idea is the same and you just need to replace the variable names.
You also mentioned in your post that you're looping from (1,1,1) till some value, (1000,15,3) and assigning a value to each of these points. If you're looping along the columns, you can replace this entire operation with a vectorized solution.
Let finalElement={1000,15,3} be the final step of the loop. As before, find the linear index as
index=sub2ind(size(A),finalElement{:});
Now if you have the values you assign in the loop stored as a single vector, values, you can simply assign it in a single step as
A(1:index)=values;

Matlab - submatrix for stiffness method

In order to use the stiffness method for trusses, I need to extract certain elements from a large global stiffness matrix.
Say I have a 9 x 9 matrix K representing a three-member truss. This means that the first 3 rows and columns correspond to the first node, the second set of three rows and columns with the second node, and the third with the third node. In the code is a vector zDisp that corresponds to each node that has zero displacement. On paper, a zero displacement of a node means you would cross out the rows and columns corresponding to that displacement, leaving you with a smaller and easier to work with K matrix. So if the first and third nodes have zero displacement, you would be left with a 3 x 3 matrix corresponding to the intersection of the middle three rows and the middle three columns.
I thought I could accomplish this one node at a time with a function like so:
function [ B ] = deleteNode( B, node )
%deleteNode removes the corresponding rows and vectors to a node that has
% zero deflection from the global stiffness matrix
% --- Problem line - this gets the first location in the matrix corresponding to the node
start = 3*node- 2;
for i = 0 : 2
B(start+i,:) = [];
B(:,start+i) = [];
end
end
So my main project would go something like
% Zero displacement nodes
zDisp = [1;
3;
];
% --- Create 9 x 9 global matrix Kg ---
% Make a copy of the global matrix
S = Kg;
for(i = 1 : length(zDisp))
S = deleteNode(S, zDisp(i));
end
This does not work because once the loop executes for node 1 and removes the first 3 rows and columns, the problem line in the function no longer works to find the correct location in the smaller matrix to find the node.
So I think this step needs to be executed all at once. I am thinking I may need to instead input which nodes are NOT zero displacement, and create a submatrix based off of that. Any tips on this? Been thinking on it awhile. Thanks all.
In your example, you want to remove rows/columns 1, 2, 3, 7, 8, and 9, so if zDisp=[1;3],
remCols=bsxfun(#plus,1:3,3*(zDisp-1))
If I understand correctly, you should just be able to first remove the columns given by zDisp:
S(remCols(:),:)=[]
then remove the rows:
S(:,remCols(:))=[]

Use a vector as an index to a matrix

I'm writing a MATLAB function to read out data into an n-dimensional array (variable dimension size). I need to be able to access a specific point in the Matrix (to write to it or read it, for example), but I don't know ahead of time how many indexes to specify.
Currently I have a current_point vector which I iterate through to specify each index, and a max_points vector which specifies the size of the array. So, if for example I wanted a 3-dimensional array of size 1000-by-15-by-3, max_points = [1000 15 3], and current_point iterates from [1, 1, 1] to [1000, 15, 3] ([1, 1, 1] -> [1000, 1, 1] -> [1, 2, 1] -> [1000, 2, 1] ->...). What I'd like to be able to do is feed current_point as an index to the matrix like so:
output_matrix(current_point) = val
But apparently something like output_matrix([1 2 3]) = val will just set outputmatrix(1:3) = 30. I can't just use dummy variables because sometimes the matrix will need 3 indexes, other times 4, other times 2, etc, so a vector of variable length is really what I need here. Is there a simple way to use a vector as the points in an index?
Using the function sub2ind to create a linear index is the typical solution to this problem, as shown in this closely-related question. You could also compute a linear index yourself instead of calling sub2ind.
However, your case may be simpler than those in the other questions I linked to. If you're only ever indexing a single point with your current_point vector (i.e. it's just an n-element vector of subscripts into your n-dimensional matrix), then you can use a simple solution where you convert current_point to a cell array of subscripts using the function num2cell and use it to create a comma-separated list of indices. For example:
current_point = [1 2 3 ...]; % A 1-by-n array of subscripts
subCell = num2cell(current_point); % A 1-by-n cell array of subscripts
output_matrix(subCell{:}) = val; % Update the matrix point
The operation subCell{:} creates the equivalent of typing subCell{1}, subCell{2}, ..., which is the equivalent of typing current_point(1), current_point(2), ....
I know it is too late but for anybody who will find this topic. the easiest way that work for me is to use: diag(A (x(:),y(:)) );
unfortunately this works only if you need to get values from the matrix, not for changing values
You can use the sub2ind function to get the linear index from the subscript.
Example:
A=magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
selectElement={2,3}; %# get the element at position 2,3 in A.
indx=sub2ind(size(A),selectElement{:});
A(indx)
ans =
10
In the above example, I've stored the subscripts (can be any number of dimensions) as a cell. If you have it stored as a vector, simply use num2cell() to convert it to a cell.
You can now easily assign a value to this as A(indx)=value;. I've used different variables than yours to keep the answer general, but the idea is the same and you just need to replace the variable names.
You also mentioned in your post that you're looping from (1,1,1) till some value, (1000,15,3) and assigning a value to each of these points. If you're looping along the columns, you can replace this entire operation with a vectorized solution.
Let finalElement={1000,15,3} be the final step of the loop. As before, find the linear index as
index=sub2ind(size(A),finalElement{:});
Now if you have the values you assign in the loop stored as a single vector, values, you can simply assign it in a single step as
A(1:index)=values;