1
$\begingroup$

Recently, I have been studying Krylov subspace iterative methods. I find the matlab robust command pcg and the new concept of the function handle to return a matrix-vector product. Then I use help pcg in matlab command window and find an example as follows:

%   compare the difference between two ways of definitions of function handle
clc;clear;
tol = 1e-6;
maxit = 15;
M = diag([10:-1:1 1 1:10]);
%%  way 1 from matlab "help pcg"
n1 = 21;
afun = @(x,n)gallery('moler',n)*x;%  returns A*x
b1 = afun(ones(n1,1),n1);
[x1,flag1,rr1,iter1,rv1] = pcg(@(x)afun(x,n1),b1,tol,maxit,M);



%%  way 2   from myself
n2 = 21;
afun = @(x)gallery('moler',n2)*x;%  returns A*x
b2 = afun(ones(n2,1));
[x2,flag2,rr2,iter2,rv2] = pcg(afun,b2,tol,maxit,M);
[iter1 iter2 flag1 flag2]
[rr1 rr2]

As you can see, the 1st way above is from matlab and I find another way to define the function handle of afun. And the numerical results is the same with matlab example. It seems that there is no difference but as we know *MATLAB** always does the best way to give us the code. So I ask whether there is any difference? Which way of function handle definition is better? Any hints and suggestions are welcome. Thanks.

$\endgroup$
2
$\begingroup$

MATLAB's definition is

afun = @(x,n)gallery('moler',n)*x;%  returns A*x

So you can pass as an argument the size n of the matrix. If you would run the code for different values of n, you simply need to declare the n and run the code, like:

for n1 = 10:21
    % do something
    b1 = afun(ones(n1,1),n1);
    [x1,flag1,rr1,iter1,rv1] = pcg(@(x)afun(x,n1),b1,tol,maxit,M);
    % do something
end

Your definition

afun = @(x)gallery('moler',n2)*x;

clearly specifies to use n2=21, so it will create a matrix 21x21, and only and exactly a matrix 21x21. If you need to run it for different values of n, you will have to define the function for every different n.

for n2 = 10:21
    % do something
    afun = @(x)gallery('moler',n2)*x;%  returns A*x
    b2 = afun(ones(n2,1));
    [x2,flag2,rr2,iter2,rv2] = pcg(afun,b2,tol,maxit,M);
    % do something
end

In the simple example above, the code will declare and create the afun variable on every loop on the for, while in MATLAB's example, the afun function is declared only once.


Edit: added execution time.

MATLAB has a good discussion on how to measure the performance of your code, but essentially you can use the timeit or the tic toc functions. To measure part of the code, you can use the tic/toc, but the recommendation to measure execution time of functions is to use timeit. The doc reads:

Unlike tic and toc, the timeit function calls your code multiple times, and, therefore, considers first-time costs.

Let's then rewrite our code to check execution time. First, define the functions:

function [] = matlabfun(num)
    %%  matlab's definition
    tol = 1e-6;  maxit = 1500;
    afun = @(x,n)gallery('moler',n)*x;
    for n1 = 10:num
        % do something
        b1 = afun(ones(n1,1),n1);
        [x1,flag1,rr1,iter1,rv1] = pcg(@(x)afun(x,n1),b1,tol,maxit);
        % do something
    end
end

function [] = myfun(num)
    %%  my definition
    tol = 1e-6;  maxit = 1500;
    for n2 = 10:num
        % do something
        afun = @(x)gallery('moler',n2)*x;%  returns A*x
        b2 = afun(ones(n2,1));
        [x2,flag2,rr2,iter2,rv2] = pcg(afun,b2,tol,maxit);
        % do something
    end
end

Then write your main script to measure the execution time of each function:

clc;clear;
num = 4e+2;%number of tests

matlab_fun = @() matlabfun(num);
my_fun = @() myfun(num);

timeit(matlab_fun)
timeit(my_fun)

The results are:

ans =

   19.9332


ans =

   19.6177

So, it looks like your definition runs faster than MATLAB's definition. In my computer, though, the difference is not that big.

However, and this I cannot explain for sure why it happens, if you change the order of the statements, you will get a different response:

clc;clear;
num = 4e+2;%number of tests

matlab_fun = @() matlabfun(num);
my_fun = @() myfun(num);

timeit(my_fun)
timeit(matlab_fun)

The results are:

ans =

   19.5554


ans =

   19.4029

Now it looks like MATLAB's definition is faster. The reason for that, and this is just my personal thoughts, is that the first call to the gallery/pcg functions takes longer than the subsequent calls. As if MATLAB has to figure out the path/library/toolbox for these functions and, since it is a first call, it runs some pieces of code to prepare your computer to run it.

This is something I have noticed along the years programming in MATLAB, the first call to a function always takes longer than the rest. So, whichever definition you put first in your code to run is the one that will take longer. I still haven't found a good explanation to why that happens, but it is how MATLAB seems to work. But, hey, just don't worry to much about that.

$\endgroup$
  • $\begingroup$ I totally get it. This proves the words that I said "MATLAB always does the best way", O(∩_∩)O. Thanks Professor Thales very much. $\endgroup$ – sunshine Nov 6 '19 at 0:14
  • $\begingroup$ But when I implement this in my matlab using a for loop, I get the contrary results listed below. Is this results right? thanks. $\endgroup$ – sunshine Nov 6 '19 at 1:41
0
$\begingroup$

Thanks Professor Thales's answer. You mean that in the for loop, matlab just declare the function handle afun once, and in my way matlab have to declare the variable afun every loop. I thought Matlab will be faster than my way, but I find the contrary results.

I have done a simple test to testify the CPU time for these two different way of definitions of function handle as follows:

clc;clear;
num = 4e+2;%number of tests
%%  matlab's definition
tic
tol = 1e-6;  maxit = 1500;
afun = @(x,n)gallery('moler',n)*x;
for n1 = 10:num
    % do something
    b1 = afun(ones(n1,1),n1);
    [x1,flag1,rr1,iter1,rv1] = pcg(@(x)afun(x,n1),b1,tol,maxit);
    % do something
end
toc


%%  my definition
tic
tol = 1e-6;  maxit = 1500;
for n2 = 10:num
    % do something
    afun = @(x)gallery('moler',n2)*x;%  returns A*x
    b2 = afun(ones(n2,1));
    [x2,flag2,rr2,iter2,rv2] = pcg(afun,b2,tol,maxit);
    % do something
end
toc

And the results are as follows (my cpu is 8GB memory, and on matlab2018b), the matlab's way is indeed slower than my way. Is this suitable for the threory? Thanks.

Elapsed time is 70.078114 seconds.
Elapsed time is 56.685017 seconds.
$\endgroup$
  • $\begingroup$ I have edited my answer adressing this issue. Check it out :) $\endgroup$ – Thales Nov 6 '19 at 10:19
  • $\begingroup$ Get it. Very thanks for your detailed and clear explanation. I have learned much from your point view. Thanks Teacher Thales again. Best wishes. $\endgroup$ – sunshine Nov 6 '19 at 10:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.