I want to call function A in a program. This function has a for loop inside and I'd like to shorten amount of iterations but not just changing the upper limit. How could I do it in this case? I was thinking if Matlab is capable of doing something like: one timer inside a function (or maybe inside a loop) and second in the main program that calls this function? But only rough idea, I'm a beginner. Please feed back if this is good idea and how could it be implemented?
thank you!
It sounds like you're talking about having a maximum elapsed time condition in your loop, something along the lines of,
MAX_T = 10;
tic;
for n=1:NMAX
% Call your loop functions
.
.
% Break if youve spent too much time in the loop
if toc > MAX_T; break; end;
end
There are also ways of optimizing this, such as only checking the value of toc every N iterations.
Related
In a MATLAB-function the following code is used:
function stuff()
if a == 2
do1();
else
do2();
end
end
This code is placed inside a simulation-loop and gets called 1000 times or more per second. The if-statement does only matter in the first call of the function, after that either do1 or do2 are used, the variable a will not change any more.
How do I prevent to waste processing time with this if-statement? Basically, how do I tell Matlab, to not check the if-statement any more, and just call the one function, that gets selected in the first call to stuff?
Contrary to your beliefs this is not a problem, the compiler (should) automatically does this optimization for you. See e.g. Loop-invariant code motion.
What you can do to help the compiler is to move the calculation of the check outside as a flag, e.g.
flag = a==2;
for i = 1:100
stuff(flag)
end
Then you only have to do the calculation once and it is clear to the compiler that the value does not change.
NOTE: Obviously, if your check really is a==2, this would not make much of a difference.
EDIT: I have not been able to definitely verify that MATLAB does this automatically. However, this is only the first layer of optimization that is done for you. All modern processors use what is called a Branch predictor, see e.g. this brilliant answer Why is processing a sorted array faster than processing an unsorted array?, or this wiki page. In short, the processor guesses the result of the if-statement, if it is correct, everything goes faster. I think it is fair to say that the processor guesses correctly in all of your cases.
TLDR: Do not wory about it.
Given the comments above, it seems what you are actually looking for is a way to dynamically chose the function to be run in your simulation. This choice should be dynamic (you do not know which function to use at runtime) but the choice should only be done once. This is easily achievable using function handles: https://www.mathworks.com/help/matlab/function-handles.html
Here is an example:
function dynamicSimulation()
if ( rand() > 0.5 ) % determine which function should be called dynamically
sim=#func1;
else
sim=#func2;
end
other_params = [];
for k = 1:5 % run the simulation
sim( k, other_params );
end
end
function func1( index, other_params )
fprintf( 'Index=%d: Simulating using function 1\n', index );
end
function func2( index, other_params )
fprintf( 'Index=%d: Simulating using function 2\n', index );
end
If you run this several times you will notice that the (random) choice of func1 or func2 will mean you do not get the same function being run each time, although the same one is used for the entire simulation.
I reckon you don't waste much time on checking the validity that if statement. However, since you specifically mention it only checks for the first iteration: why not get that out? So instead of:
for ii = 1:10
if ii == 1
k = 1;
else
k = k + 1;
end
end
You could do
k = 1;
for ii = 2:10
k = k + 1;
end
Thus eliminating the check.
NB: this scales badly of course, but as it is only a single iteration here I consider it a good option.
I know that it seems like the straightforward answer is NO. Yet, I wonder if there is not a way to get it to work.
Basically, I would like to randomly draw from a distribution and only keep those who respect a certain condition and fill a pre-determined storage matrix and stop once the matrix is full.
Since these are draw, I suppose I can harness Matlab's parallel capabilities but since the completion of the storage matrix depends on the sequence of draws, I feel there is an issue there.
Alternatively, is there a way to use a time-check for the problem at hand. For instance, I would use a parfor with a limit absurdely large but include a way to check the size of the storage matrix at frequent interval.
In pseudo-code, it would give:
create size of the storage matrix: A=zeros(100,1); Naccepted=0;Ntried=0;
initiate the for loop: parfor i=1:100000000000
do the loop: x(i)=randn(1,1)
check whether it respects the condition: if x(i)>0, Naccepted=Naccepted+1; Ntried=Ntried+1; A(j,1)=x(i), else Ntried=Ntried+1
Check with a timer every 5 minutes (that I have no clue as to implement it in Matlab) if the size of A has reached 100 or not. If so, then stop and take the first 100 accepted draw. If not, continue.
I realize that my question is very messy but I fail to see properly which part could work in parallel or not.
Ok, figured it out:
matlabpool open 8
tic
clear;
j=1;
Naccepted=0;
A=[];
workers=8;
while size(A,1)<=100
spmd(workers)
x=zeros(10,1);
for i=1:10
x(i)=randn(1,1);
end
end
for k=1:workers
Z(:,k)=x(1,k);
end
for k=1:workers
V(1+(k-1)*10:10+(k-1)*10,1)=cell2mat(Z(1,k));
end
V=V(V>0);
A=[A;V];
Naccepted(j,1)=size(V,1);
j=j+1;
end
Ntried=j*workers*10;
rejection=1-sum(Naccepted)/Ntried;
A=A(1:100,1);
toc
matlabpool close
Using a while loop directly is not possible, however, there is a small trick that can be used.
A while loop can be decomposed into a for loop in combination with checking the same condition as the while loop.
If it is possible to use a for loop, it can be possible, given suitable use of the variables inside the loop (broadcast, slice, etc), to use a parfor loop.
To give you an example:
clear
nb_tests=1e8;
tic
i=1;
captured=zeros(1,nb_tests);
while i<nb_tests
tester=rand;
if tester>0.5
captured(i)=tester;
i=i+1;
end
end
toc
tic
captured=zeros(1,nb_tests);
for i=1:nb_tests
respect=0;
while respect<1
tester=rand;
if tester>0.5
captured(i)=tester;
respect=1;
end
end
end
toc
parpool
tic
captured=zeros(1,nb_tests);
parfor i=1:nb_tests
respect=0;
while respect<1
tester=rand;
if tester>0.5
captured(i)=tester;
respect=1;
end
end
end
toc
Be advised that the advantage of parallelization kicks in when you either have a lot of iterations or when the content of the loop is more complex.
I am an amateur Matlab User who is attempting to write a code to run a specific function call every 10ms for a time span of 1 second. I am having trouble trying to get something to run for the exact amount of time; I have tried to use Tic and Toc but that's in seconds (I need millisecond precision). Here is some very basic code I have been playing with to try and get readings using a function called getvelocity. Any help would be appreciated, thanks!
function [ velocity ] = Vel()
i=1;
timerID=tic;
while (toc(timerID) <=2);
[v(i)]=vpx_GetTotalVelocity;
disp (v(i));
i=i+1;
end
velocity=mean(v);
end
The code above runs for two seconds; however, I want to run in ms precision.
Assuming the function you have is fast enough (not a trivial assumption) you can achieve it like so:
tic
for t = 0.01:0.01:1 %If you want the first function call to start right away you can change this to 0:0.01:0.99
while toc < t
end
t %Put your function call here.
end
Note that 0.01 sec is 10 ms
i want fsolve to calculate the output for different uc each time (increasing uc by 0.001 each time). each output from fsolve should be sent to a simulink model seperatly. so i set a loop to do so, but i believe that at the currenty constellation (if it will work)will just calculate 1000 different values? is there a way to send out the values seperately?
if not, how can i create a parameter uc. that goes from 0 to say 1000? i tried uc=0:0.001:1000, but again, the demension doen't seem to fit.
how do i create a function that takes the next element of a vector/matrix each time the function is called?
best regards
The general approach to iterating over an array of values and feeding them one-by-one into a series of evaluations of a function follows this form:
for ix = 0:0.1:10
func(arg1, arg2, ix)
end
See how each call to func includes the current value of ix ? On the first iteration ix==0, on the next ix==0.1 and so forth. You should be able to adapt this to your needs; in your code the loop index (which you call i) is not used inside the loop.
Now some un-asked-for criticism of your code. The lines
x0=[1,1,1];
y=x0(1);
u=x0(2);
yc=x0(3);
options=optimset('Display','off');
do not change as the loop iterations advance; they always return the same values whatever the value of the loop iterator (i in your code) may be. It is pointless including them inside the loop.
Leaving them inside the loop may even be a waste of a lot of time if Matlab decides to calculate them at every iteration. I'm not sure what Matlab does in this case, it may be smart enough to figure out that these values don't change at each iteration, but even if it does it is bad programming practice to write your code this way; lift constant expressions such as these out of loops.
It's not clear from the fragment you've posted why you have defined y, u and yc at all, they're not used anywhere; perhaps they're used in other parts of your program.
Why is indexing into a dataset array so slow? A peak into the dataset.subsref function shows that all the columns of the dataset are stored in a cell array. However, cell indexing is much, much faster than dataset indexing, which is just indexing into a cell array under the hood. My guess is that this has to do with some overhead with MATLAB OOP. Any ideas on how to speed this up?
%% Using R2011a, PCWIN64
feature accel off; % turn off JIT
dat = (1:1e6)';
dat2 = repmat({'abc'}, 1e6, 1);
celldat = {dat dat2};
ds = dataset(dat, dat2);
N = 1e2;
tic;
for j = 1:N
tmp = celldat{2};
end
toc;
tic;
for j = 1:N
tmp2 = ds.dat2; % 2.778sec spent on line 262 of dataset.subsref
end
toc;
feature accel on; % turn JIT back on
Elapsed time is 0.000165 seconds.
Elapsed time is 2.778995 seconds.
EDIT: I've updated the example to be more like the problem I'm seeing. A huge amount of time is spent on line 262 of dataset.subsref - "b = a.data{varIndex};". It's very strange to me since it is a simple cell dereference. I'm wondering if there is a OOP trick that will allow me to index into "a.data" without the strange overhead.
EDIT2: As per Andrew's suggestion, I've submitted this as a bug to MatWorks. Will update if I hear anything from them.
EDIT3: Matlab responded and said they are aware of the problem now and will fix it in a future release. They noted that the problem is specific to cell arrays, and to try to avoid them if possible.
Yes, you are most likely seeing the overhead of Matlab OOP method calls. They are expensive compared to cell indexing, or method calls in some other languages. Your .513872 seconds / 1e4 ~= 51 microseconds per call, which is the approximate cost of a few MCOS method calls; they're ~5-15 microsececonds each on machines I've seen. So that looks like method overhead of the subsref() call itself and other methods and property accesses it's calling in turn.
For some details and discussion, see: Is MATLAB OOP slow or am I doing something wrong?
I don't know of a way to make this faster, aside from structuring your code to minimize calls to "ds.dat" or other methods. If possible, when working with the data set, call "ds.dat" once, keep it in a local variable and work with it there, and then push it back in to the ds object.
Caveat: I don't know what "feature accel" does or how it could affect these timings.
Edit: I threw it in the profiler like Richie suggested. On my R2009b, looks like about half the time is method call overhead, and the rest in find(), strcmp(), and other operations inside subsref; subsref doesn't call any other methods in turn.
Edit 2: The revised example is showing much higher timings. Method call overhead doesn't account for all that.