Storing multiple powers of matrices in matlab [duplicate] - arrays

This question already has answers here:
How to generate the first twenty powers of x?
(4 answers)
Closed 7 years ago.
I have 1000 matrices with dimensions 2x2.
What I now need to do is to get 30 consecutive powers of those matrices (A^2, A^3... ...A^30) and store them all.
I found a topic that suggested using bsxfun:
Vectorizing the creation of a matrix of successive powers
However, bsxfun does not work with cell arrays ("Error using bsxfun
Operands must be numeric arrays").
What can I do?
PS. A secondary question: once I have them, I want to plot 4 graphs (each corresponding to 1 of the elements of the 2x2 matrices) with 30 positions (x-axis) which will show confidence bands (16th and 84th percentile).
EDIT: Someone linked to a question that was similar to the one that I linked. From what I can understand, the question there is about a vector, not array of matrices.

Assuming your array A is 2-by-2-by-1000, here are two loops to make things work:
A = rand(2,2,1000);
K = 30;
%%
N = size(A,3);
APower = zeros(2,2,N,K);
APower(:,:,:,1) = A;
for i = 1:N
for k = 2:K
APower(:,:,i,k) = A(:,:,i)*APower(:,:,i,k-1);
%// Alternatively you could use:
%APower(:,:,i,k) = A(:,:,i)^k;
end
end

You need to replicate the matrix 30 times to do this using cellfun. For example,
a = repmat(A{1},1,30);% Select one of your A matrices
b = num2cell(1:30);
x = cellfun(#(a,b) a^b,a,b,'UniformOutput',false)
Since you need to run cellfun for each element of A another way is to use arrayfun as below.
a = A{1};
b = 1:30;
x = arrayfun(#(b) a^b,b,'UniformOutput',false)

Related

Count values in a vector less than each one of the elements in another vector

I have two vectors r and d and I'd like to know the number of times r<d(i) where i=1:length(d).
r=rand(1,1E7);
d=linspace(0,1,10);
So far I've got the following, but it's not very elegant:
for i=1:length(d)
sum(r<d(i))
end
This is an example in R but I'm not really sure this would work for matlab:
Finding number of elements in one vector that are less than an element in another vector
You can use singleton expansion with bsxfun: faster, more elegant than the loop, but also more memory-intensive:
result = sum(bsxfun(#lt, r(:), d(:).'), 1);
In recent Matlab versions bsxfun can be dropped thanks to implicit singleton expansion:
result = sum(r(:)<d(:).', 1);
An alternative approach is to use the histcounts function with the 'cumcount' option:
result = histcounts(r(:), [-inf; d(:); inf], 'Normalization', 'cumcount');
result = result(1:end-1);
You may build a matrix flagging values from vector r inferior to values from vector d in one time with bsxfun, then sum the values:
flag=bsxfun(#lt,r',d);
result=sum(flag,1);
For each element in d, count how many times this element is bigger than the elements in r, which is equivalent to your problem.
r=rand(1,10);
d=linspace(0,1,10);
result = sum(d>r(:))
Output:
result =
0 0 1 2 7 8 8 8 9 10

Matlab matrix indexing from 2 Arrays (X,Y) [duplicate]

This question already has answers here:
Two arrays defining 2D coordinates, as array indices
(2 answers)
Closed 2 years ago.
I have X and Y positions for a large array and I would like to use them to define what the contents of that position. I could run a for loop to define the positions but I think there would be a faster method. I tried to use the array position define function.
x = [6,2,3]
y = [1,2,3]
c = [1,1,1,2,2,3;...
1,1,1,2,2,5;...
2,2,1,4,2,3;...
1,1,4,3,2,3;...
1,2,3,4,5,3;...
1,2,3,5,4,2];
When I type the equation above it results in the answer below
c(y,x)
ans =
1 2 3
1 1 1
2 2 1
What I'm looking for are the 1:1 positions from the arrays.
c(y(1),x(1))
c(y(2),x(2))
c(y(3),x(3))
Is there any way to limit the arrays to a linear sequence? my only guess right now is to reshape the arrays into a cell matrix containing the individual a and b and then perform a cellfun. but I think I'm making it to complicated.
You have to convert the locations into linear indices first, then you can grab the correct elements in the desired linear sequence. You can use sub2ind to help you do that:
ind = sub2ind(size(c), y, x); % Get linear indices
v = c(ind); % Get the elements
Doing this thus gives:
>> v = c(ind)
v =
3 1 1
You can verify for yourself that each pair of (y,x) gives you the right element you're looking for. For example, when y = 1 and x = 6, the element retrieved is 3 and so on.

Compute the product of the next n elements in array

I would like to compute the product of the next n adjacent elements of a matrix. The number n of elements to be multiplied should be given in function's input.
For example for this input I should compute the product of every 3 consecutive elements, starting from the first.
[p, ind] = max_product([1 2 2 1 3 1],3);
This gives [1*2*2, 2*2*1, 2*1*3, 1*3*1] = [4,4,6,3].
Is there any practical way to do it? Now I do this using:
for ii = 1:(length(v)-2)
p = prod(v(ii:ii+n-1));
end
where v is the input vector and n is the number of elements to be multiplied.
in this example n=3 but can take any positive integer value.
Depending whether n is odd or even or length(v) is odd or even, I get sometimes right answers but sometimes an error.
For example for arguments:
v = [1.35912281237829 -0.958120385352704 -0.553335935098461 1.44601450110386 1.43760259196739 0.0266423803393867 0.417039432979809 1.14033971399183 -0.418125096873537 -1.99362640306847 -0.589833539347417 -0.218969651537063 1.49863539349242 0.338844452879616 1.34169199365703 0.181185490389383 0.102817336496793 0.104835620599133 -2.70026800170358 1.46129128974515 0.64413523430416 0.921962619821458 0.568712984110933]
n = 7
I get the error:
Index exceeds matrix dimensions.
Error in max_product (line 6)
p = prod(v(ii:ii+n-1));
Is there any correct general way to do it?
Based on the solution in Fast numpy rolling_product, I'd like to suggest a MATLAB version of it, which leverages the movsum function introduced in R2016a.
The mathematical reasoning is that a product of numbers is equal to the exponent of the sum of their logarithms:
A possible MATLAB implementation of the above may look like this:
function P = movprod(vec,window_sz)
P = exp(movsum(log(vec),[0 window_sz-1],'Endpoints','discard'));
if isreal(vec) % Ensures correct outputs when the input contains negative and/or
P = real(P); % complex entries.
end
end
Several notes:
I haven't benchmarked this solution, and do not know how it compares in terms of performance to the other suggestions.
It should work correctly with vectors containing zero and/or negative and/or complex elements.
It can be easily expanded to accept a dimension to operate along (for array inputs), and any other customization afforded by movsum.
The 1st input is assumed to be either a double or a complex double row vector.
Outputs may require rounding.
Update
Inspired by the nicely thought answer of Dev-iL comes this handy solution, which does not require Matlab R2016a or above:
out = real( exp(conv(log(a),ones(1,n),'valid')) )
The basic idea is to transform the multiplication to a sum and a moving average can be used, which in turn can be realised by convolution.
Old answers
This is one way using gallery to get a circulant matrix and indexing the relevant part of the resulting matrix before multiplying the elements:
a = [1 2 2 1 3 1]
n = 3
%// circulant matrix
tmp = gallery('circul', a(:))
%// product of relevant parts of matrix
out = prod(tmp(end-n+1:-1:1, end-n+1:end), 2)
out =
4
4
6
3
More memory efficient alternative in case there are no zeros in the input:
a = [10 9 8 7 6 5 4 3 2 1]
n = 2
%// cumulative product
x = [1 cumprod(a)]
%// shifted by n and divided by itself
y = circshift( x,[0 -n] )./x
%// remove last elements
out = y(1:end-n)
out =
90 72 56 42 30 20 12 6 2
Your approach is correct. You should just change the for loop to for ii = 1:(length(v)-n+1) and then it will work fine.
If you are not going to deal with large inputs, another approach is using gallery as explained in #thewaywewalk's answer.
I think the problem may be based on your indexing. The line that states for ii = 1:(length(v)-2) does not provide the correct range of ii.
Try this:
function out = max_product(in,size)
size = size-1; % this is because we add size to i later
out = zeros(length(in),1) % assuming that this is a column vector
for i = 1:length(in)-size
out(i) = prod(in(i:i+size));
end
Your code works when restated like so:
for ii = 1:(length(v)-(n-1))
p = prod(v(ii:ii+(n-1)));
end
That should take care of the indexing problem.
using bsxfun you create a matrix each row of it contains consecutive 3 elements then take prod of 2nd dimension of the matrix. I think this is most efficient way:
max_product = #(v, n) prod(v(bsxfun(#plus, (1 : n), (0 : numel(v)-n)')), 2);
p = max_product([1 2 2 1 3 1],3)
Update:
some other solutions updated, and some such as #Dev-iL 's answer outperform others, I can suggest fftconv that in Octave outperforms conv
If you can upgrade to R2017a, you can use the new movprod function to compute a windowed product.

Address each Matlab array element, one by one, independent from dimension (row vs. column) [duplicate]

This question already has an answer here:
Why, if MATLAB is column-major, do some functions output row vectors?
(1 answer)
Closed 7 years ago.
I would like to do something with each element in an array. For a row array, I can do this:
array = [1 2 3];
i = 0;
for a = array
i = i + 1;
end
fprintf('Number of iterations: %g\n', i)
Number of iterations: 3
It will output 3, so it actually accessed each array element one after another.
However if the array is a column, the same code will output just 1:
array = [1; 2; 3];
...
Number of iterations: 1
I wonder why exactly this happens and if there is a way to iterate through an array, independent from its "directional dimension" and without using for i = 1:numel(array), a = array(i).
When a for loop is initialized with an array, it iterates column by column. This may not be what you want, but that the built in behavior (see http://www.mathworks.com/help/matlab/ref/for.html).
You can force your matrix into a linear row vector, so MATLAB will iterate the elements 1 by 1 with the following:
for i = A(:)'
i % use each value of A
end
Normally, a combination of vector operations will be faster than a for loop, so only use a for loop when you can't think of the appropriate vector operation equivalent.

Repeat values in array n-times with different values for n [duplicate]

This question already has answers here:
Repeat copies of array elements: Run-length decoding in MATLAB
(5 answers)
Closed 7 years ago.
I'm having problems with the following task. I have a dummy array of zeros and 2 vectors of equal size. For example:
array1 = zeros(750,1);
vector1 = [1;3;5];
vector2 = [100;250;400];
I am looking to fill array1 as follows:
repeat element 1 in vector1 100 times
repeat element 2 in vector2 250 times
repeat element 3 in vector1 400 times
The resulting vector should have 7 rows and 1 column. I tried playing around with repmat but can't get it to output only 1 dimension. I also heard about bsxfun but I never end up with the data I need. I'm grateful for any useful suggestions.
I have Matlab 2013, so I'm not able to use the fancy function repelem that I found might be useful.
array1(1:100) = vector1(1);
array1(101:350) = vector2(2);
array1(351:750)=vector1(3);
though why the total length is 2850 is beyond me.
Maybe something like:
vector1 = [1;3;5];
vector2 = [100;250;400];
temp = linspace(1,sum(vector2),sum(vector2))';
array1 = zeros(size(temp));
for ii = 1:length(vector2)
array1 = array1 + (temp <= sum(vector2(1:ii)) & not(array1))*vector1(ii);
end
clear temp ii

Resources