Alternative to circshift function?

24 views (last 30 days)
In reference to this question.
The documentation states that there was a modification during R2016b. I was wondering if there is any update to alternative ways to optimize for time since I end up calling this function almost 3.85 million times. Bear in mind that I did not originally make this code so I'm trying to understand how to use this function within the loop. Also, I know I could try to reduce the iterations, but I haven't yet figured that part out since there is a lot of math operations within this nested loop. I have a shift that is not constant, therefore the answer to the referenced question is not going to solve this problem.
Note: Sorry for the lack of details. I tried to keep it simple, the variable names and function names would add unnecessary complexity for those not familiar with it. Basically, if anyone can simply provide an alternative method to using circshift, I would appreciate it!
a_matrix = zeros(num_p_considered,len); %pre-allocate
for m = 1:6
kk = a_vector(m); %length is 6
[complex_vec(m), a_vector2(m)] = a_function(var); % 6x1 vector outputs
a_scalar = ceil(a_vector2(m));
a_scalar2 = floor((a_scalar - a_vector2(m)) * 1000);
if a_scalar2 == 0
a_scalar2 = 1000;
end
a_vector3 = circshift(a__predefined_matrix(:,a_scalar2), a_constant + a_scalar); % 81880x1 vector output
% some other math operations that use above stuff
end
Edit
I was able to make a custom function in a very simple format. There exists a vector of length 81880, to which I want to circularly shift and truncate to length of 8000. Here is the code snippet:
tempN = k2 + tmp_tau_m_l_integer2;single_vec(1 : (8000 - tempN)) ];
tmp_p_t3 = [single_vec(81880-tempN+1:81880); single_vec(1:8000-tempN) ];
% tmp_p_t3 is [8000x1]
tmp_p_t_m2 = circshift( single_vec, k2 + integer2);
tmp_p_t2(kth_element2,:) = abs( tmp_p_t_m2(1:len))';
% tmp_p_t2 is [8000x1]
for n = 1:8000
OK_if_true(n) = max(max(max(max(abs((tmp_p_t3(n) - tmp_p_t2(kth_element,n))^2))))) < 1e-3;
a = find(OK_if_true); % identify the ones exact
end
where kth_element is the current inner loop, k2 is the current outer loop, integer2 is the variable that changes every iteration, len = 8000, and single_vec is a constant set of numbers. Essentially, single_vec is a list of "guesses" in double precision and we are circularly shifting to guess in different ways.
Lastly, I use the last chunk of the code to compare for exactness. Unfortunately, all but elements 3437-3519 are true that the difference is either minute or they are exactly the same. So how could my indexing operation be incorrect in only 87 elements within the vector that was concatenated?
To include some more detail. I can change the 'eps' variable to 1e-7 and I see that there are 56 matching elements. A similar structured code in all integer format would prove that this should work. I'm not sure what is going on here.
Here is a simple example of the same structure by itself:
a = (2.7 : .22245786443 : 7.68).'; % length: 23
n = 5;
tic
b = circshift(a,n);
b = b(1:20); % truncate to length of 20
toc
tic
c = [ a(23-n+1 : 23) ; a(1 : 20-n) ]; % notice the structure here with the one above
toc
OK_if_true = max(max(max(max(abs(b - c))))) < eps
  5 Comments
Rik
Rik on 11 Jul 2017
It might be worth going to the trouble of generating a cell array in which each element contains the indices for the next circshift. So p{1}=[11,1:10];p{2}=[10:11,1:9];p{3}=[9:11,1:8]; (of course generating this in a loop with circshift will be easier and less prone to errors)
If you want to ignore an explicit statement in the documentation and a comment by a staff member, go ahead. I will take either of those as sufficient proof there is a difference since R2016b.
However, I think that is not relevant for your question. I think the root of your question is not the changed behavior, but you wanting a more efficient way to do things than circshift. Because you are calling it so often, creating that potentially huge helper array might be worth it. Just test it.
Tyler Warner
Tyler Warner on 14 Jul 2017
Awesome! That may be worth the initial overhead. I can probably figure out a way to vectorize the operation ahead of time like you mentioned. Thanks Rik Wisselink.

Sign in to comment.

Accepted Answer

Jan
Jan on 11 Jul 2017
Edited: Jan on 11 Jul 2017
According to the documentation all you have to change for a perfect backward compatibility is:
a_vector3 = circshift(a__predefined_matrix(:,a_scalar2), a_constant + a_scalar, 1);
But as long as the input is a vector, omitting the dimension will produce the same result.
Before you try to optimize circshift (which can be done by inlining the code and removing the input checks), use the profile'r to find the bottlenecks of the code. If the main work is done inside a_function and circshift needs only 2% of the runtime, incresing its speed by a factor of 2 will gain in a total speedup of 1% only. Do not waste programming time with optimizing marginal functions.
The inlined circshift:
nShift = a_constant + a_scalar;
len = size(a__predefined_matrix, 1);
index = mod((0:len-1)-nShift, len) + 1;
a_vector3 = a__predefined_matrix(index, a_scalar2);
  4 Comments
Tyler Warner
Tyler Warner on 28 Jul 2017
Thank you, the answer was not quite what I had done, but I took a deeper look into how exactly this new variable was changing every loop. It ended up being a trivial answer hidden behind a lot of operations. I was able to cut the lines from about 6 to 2 by using indexing.
For example:
circshift(vector,x)
can be replaced by
len = length(vector);
vector = [ vector( len-x+1 : len ) : vector( 1 : len-x ) ];
which technically could be in one line, but I did this for readability. I got to this after reading the answer as well as the comments and my supervisor helping out. Thanks everyone!
Muzammil Naeem
Muzammil Naeem on 10 Sep 2020
len = length(vector);
vector = [ vector( len-x+1 : len ) vector( 1 : len-x ) ];
I just have removed : between them now its working properly

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!