Matlab vectorization of vector creation [duplicate] - matlab

This question already has answers here:
Element-wise array replication according to a count [duplicate]
(4 answers)
Closed 8 years ago.
I would like to vectorize the creation of the following vector:
For example-
Let A be a vector [5 3 2 1]
And let B be a vector [1 2 3 4]
I would like C to be the vector [1 1 1 1 1 2 2 2 3 3 4]
Meaning- each element i in B is duplicated A(i) times in C.
I haven't found a way to vectorize the creation of this, any ideas?
Thanks in advance!
Ronen

Approach #1
Here's one approach if B doesn't have any zeros -
C = nonzeros(bsxfun(#times,bsxfun(#le,[1:max(A)]',A),B))
Approach #2
A general case solution -
mask = bsxfun(#le,[1:max(A)]',A) %//'
B_ext = bsxfun(#times,mask,B)
C = B_ext(mask)
Approach #3
cumsum based approach and must be pretty efficient one -
idx = [1 cumsum(A(1:end-1))+1] %// indices where each new B values start
C = zeros(sum(A),1) %// storage for output
C(idx) = diff([0 B]) %// put those values, but offseted
C = cumsum(C) %// finally get the output

Related

MATLAB - convert vector to unit vector [duplicate]

This question already has answers here:
Normalizing rows of matrix, so that their norm is equal to 1 (MATLAB)
(2 answers)
Closed 6 years ago.
I have a vector:
vector = [1 2 3;4 5 6; 7 9 0]
vector =
1 2 3
4 5 6
7 9 0
I want to take this and create a unit vector. We can get the magnitude by doing:
mag = sqrt(sum(vector'.^2))'
mag =
3.7417
8.7750
11.4018
When we try to divide each element by the magnitude I get an error:
vector./mag
Error using ./
Matrix dimensions must agree.
Essentially I must divide every vector element in each row by every row in the mag vector. How can I do this?
The other answers give the correct result but you can vectorize the calculation for faster calculation.
ret = bsxfun(#rdivide, vector, mag)
I recommend using the bsxfun, it is a very useful function for matrix calculation.
The problem is that, as the error message says, the dimensions of vector and mag don't match.
You want to divide every element of the first row of vector by mag(1).
What you need is repmat(), which "repeats copies of array".
Writing
repmat(mag,1,3)
returns a 3x3 matrix such that every column is an exact copy of mag:
3.7417 3.7417 3.7417
8.7750 8.7750 8.7750
11.4018 11.4018 11.4018
So you can use the one-liner:
vector./repmat(mag,1,3)
ans =
0.26726 0.53452 0.80178
0.45584 0.56980 0.68376
0.61394 0.78935 0.00000
That way, the first row of vector, i.e., [1 2 3], is divided element-by-element by [3.7417 3.7417 3.7417].
In other words, every element of vector is divided by the correct magnitude.
You can use matrix operators in MATLAB:
result = diag(1./mag)*vector;
If dimension of mag can be too big you can use sparse version of it:
result = spdiags(1./mag,0,speye(numel(mag)))*vector;
A simple solution is the use of a for-loop:
vector = [1 2 3; 4 5 6; 7 9 0];
mag = sqrt(sum(vector'.^2))';
A = [];
for i = 1:numel(mag)
A(i,:) = vector(i,:)./mag(i);
end
vector = [1 2 3; 4 5 6 ;7 9 0] ;
[n,m]=size(vector);
for i=1:n
normv=norm(vector(i,:),2);
nvector(i,:)=vector(i,:)/normv;
end
the nvector will contain the normalized vector of each line

Calculate the first N terms of a geometric sequence in Matlab [duplicate]

This question already has answers here:
Common way to generate finite geometric series in MATLAB
(2 answers)
Closed 7 years ago.
How to calculate the first N terms of the geometric sequence Un = 2^n in Matlab?
Are there any Matlab functions that I'm not aware of to facilitate this? or do I have to pick a math book to understand this and implement it in a for loop or something?
Any links to similar Matlab code would be appreciated, or if you could explain it for me that would be appreciated!
First, you set the N terms for your sequence, i.e.:
N = 10 %//set first 10
Now you want to make a vector from 1 to N, i.e.:
n= [1:N]
Un = 2.^n %//Note the dot is very important! I almost forgot
%//ans = [2,4,8,16...1024]
This would make function a vector of 1 by N where each element is the corresponding answer to your function.
for your second question (in comment)
you want to do something like:
Bflip = B' %//This flips the matrix B so that what use to be column is now rows
So Bflip would be the result you want, I tested with your example:
A = [2 2 2;4 4 4; 6 6 6];
B = [0 0 0; 1 1 1; 2 2 2];
Bflit = [ 0 1 2
0 1 2
0 1 2]
This will generate a 3 dimension matrix. To call on each of the 4 sets of results, just do something like result1 = permutation(:,:,1)

Extract fixed amounts of data from array based on a list of indices

I have the array
a=1:20
and a series of indices which indicate where I want to start pulling data out:
i=[4,12]
For each index i, I want that index and the next four (well, x, really) elements in a column or row. I'll avoid getting to close to the end of the array, so that special case can be disregarded.
If I was hard-coding this, I could use:
a([4:8;12:16])
and this would achieve my result.
But i may have many different values.
Any thoughts on how I can transform a list of indices into a matrix of ranges, or other ways to solve this problem?
EDIT
I am using Matlab 2007; it would be preferable if the solution relied solely on Matlab's internals and toolboxes. bsxfun is not present until 2007a.
Let i be your indicesx and x the number of elements you want in addition to the elements in i, then you can use
i = [4 6 8];
x = 4;
bsxfun(#plus, 0:x, i(:))
to get a matrix of indices:
ans =
4 5 6 7 8
6 7 8 9 10
8 9 10 11 12
If you do not have access to bsxfun you can use repmat instead:
i = [4 6 8];
x = 4;
repmat(i(:), 1, x+1) + repmat(0:x, length(i), 1)
Here is a solution without bsxfun but with repmat inspired by the previous answer.
i = [4 6 8];
x = 4;
p = repmat(1:x,length(i),1);
q = repmat(i',1,x);
p+q

Interleaved repmat [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Element-wise array replication in Matlab
I have a m x 1 vector that I would like to repeat n times to create a (m*n)x1 vector. If I use repmat, I get something like
>> V = [a;b;c];
>> repmat(V,2,1) % n = 2, m = 3
a
b
c
a
b
c
What would be a one-line (and hopefully fast) way of getting the vector
[a;a;a;b;b;b;c;c;c]
for arbitrary n and m?
V=[ 1;2;3];
reshape(repmat(V',3,1),[],1)
ans =
1
1
1
2
2
2
3
3
3

How to efficiently access/change one item in each row of a matrix

I have a matrix A with size (nr,nc), a vector of column indices B (so B has size (nr,1) and every element in B is an integer between 1 and nc), and I want to do something to every element in A that is of the form A(i,B(i)) for i between 1 and nr, efficiency being the key concern.
For concreteness, say C is a vector of size (nr,1), the goal is to do
for i=1:nr
A(i,B(i))=A(i,B(i))+C(i)
end
more efficiently. The context is usually that nr>>nc (because when nr is large vectorization is efficient for many operations). I have gotten a factor 3 speedup by using an indicator function approach:
for k=1:nc
A(:,k)=A(:,k)+(k==B).*C
end
Are there other ways (more efficient hopefully) to do this?
I guess this is similar to many questions on double-indexing, but it's concretely one I run into all the time.
Use linear indexing:
idx = sub2ind(size(A), 1:nr, B');
A(idx) = A(idx) + C';
or (edited version with one less transpose)
idx = sub2ind(size(A), (1:nr)', B);
A(idx) = A(idx) + C;
One way would be to use linear indexing of the matrix. You will need a vector v holding the offsets of the first element in each line, then index using A(v + B). For example:
>A=[1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
>B = [1 2 3] % we want the 1st element of row 1, 2nd of row 2, 3rd of row 3
>ii = [0 3 6] + B
>a(ii)
1 5 9
Note: As groovingandi had shown, it is also possible (and more readable) to use sub2ind to generate the ii linear indices vector. The idea is essentially the same.