Search code examples
matlabmatrixplotnumerical-methods

Plotting multiple vectors of different lengths on the same figure


I am currently working on a project in MATLAB that compares two different numerical methods (direct and iterative), each for two different matrix sizes, to the actual analytic solution of the system. The first .m file included below provides an implementation of a tridiagonal matrix solver, where the main function plots a solution for two different sizes of tridiagonal matrices: a 2500x2500 matrix and 50x50 matrix.

function main
n=50; 
for i=1:2
di=2*ones(n,1);
up=-ones(n,1);
lo=-ones(n,1);
b=ones(n,1)/(n*n); 
[subl,du,supu]=tridiag_factor(lo,di,up);
usol = tridiag_solve(subl,du,supu,b);
%figure(i)
plot(usol);
hold on;
title(['tridiag ' num2str(n) '']) 
n=2500; 
end


function [subl,du,supu]=tridiag_factor(subd,d,supd)
n=length(d);
for i=1:n-1
subd(i)=subd(i)/d(i);
d(i+1)=d(i+1)-subd(i)*supd(i);
end
subl=subd; supu=supd; du=d;

function x = tridiag_solve(subl,du,supu,b)

% forward solve
n=length(b); z=b; 
z(1)=b(1);
for i=2:n
z(i)=b(i)-subl(i)*z(i-1);
end
% back solve
x(n)=z(n);
for i=n-1:-1:1
x(i)=(z(i)-supu(i)*x(i+1))/du(i);
end

I have included a hold on statement after the first usol is plotted so I can capture the second usol on the same figure during the second iteration of the for loop. The next piece of code is a Jacobi method that iteratively solves a system for a tridiagonal matrix. In my case, I have constructed two tridiagonal matrices of different sizes which I will provide after this piece of code:

function [xf,r] = jacobi(A,b,x,tol,K)
%
%  The function jacobi applies Jacobi's method to solve A*x = b.
%  On entry:
%    A       coefficient matrix of the linear system;
%    b       right-hand side vector of the linear system;
%    x       initial approximation;
%    eps     accuracy requirement: sx=top when norm(dx) < eps;
%    K       maximal number of steps allowed.
%  On return:
%    x       approximation for the solution of A*x = b;
%    r       residual vector last used to update x,
%            if success, then norm(r) < eps.[
%
n = size(A,1);
fprintf('Running the method of Jacobi...\n');
for k = 1:K
      % r = b - A*x;
    for i=1:n
        sum=0;
        for j = 1:n
            if j~=i
                sum=sum+A(i,j)*x(j);
            end
        end
        x(i)=(b(i)-sum)/(A(i,i));
    end;
    k=k+1;
    r = b - A*x;
%     fprintf('  norm(r) = %.4e\n', norm(r));
    if (norm(r) < tol)
        fprintf('Succeeded in %d steps\n', k);
        return;
    end;
end
fprintf('Failed to reached accuracy requirement in %d steps.\n', K);
xf=x;

%r(j) = r(j)/A(j,j);
%x(j) = x(j) + r(j);

Now, lastly, here is my code for the two tridiagonal matrices (and other related information for each system corresponding to the appropriate matrices) I wish to use in my two jacobi function calls:

% First tridiagonal matrix 
n=50; 
A_50=full(gallery('tridiag', n, -1, 2, -1));

% Second tridiagonal matrix 
n=2500; 
A_2500=full(gallery('tridiag', n, -1, 2, -1));

K=10000;
tol=1e-6;

b_A50=ones(length(A_50), 1);
for i=1:length(A_50)
    b_A50(i,1)=0.0004;
end 
x_A50=ones(length(A_50),1);


b_A2500=ones(length(A_2500), 1);
for i=1:length(A_2500)
    b_A2500(i,1)= 1.6e-7;
end 
x_A25000=ones(length(A_2500),1);

As stated in the question header, I need to plot the vectors produced from jacobi(A_50,b_A50,x_A50,tol,K), jacobi(A_2500,b_A2500,x_A25000,tol,K) and a mathematical function y=@(x) -0.5*(x-1)*x all on the same figure along with the two usol (for n=50 and n=2500) produced by the main function shown in the first piece of code, but I have had no luck due to the different lengths of vectors. I understand this is probably an easy fix, but of course my novice MATLAB skills are not sufficing.


Note: I understand x_A50 and x_A2500 are trivial choices for x, but I figured while I ask for help I better keep it simple for now and not create any more issues in my code.


Solution

    1. In MATLAB traces sent to same plot must have same length.

    2. I have allocated just one variable containing all traces, for the respective tridiagonals and resulting traces out of your jacobi function.

    3. I have shortened from 2500 to 250, and the reason is that with 2500, compared to 50, the tridiag traces, and the short jacobi are so flat compared to the last trace than one has to recur to dB scale to find them on same graph window as you asked.

    4. 1st generate all data, and then plot all data.

    So here you have the script plotting all traces in same graph :

    clear all;close all;clc
    
    n=[50 250]; 
    
    us_ol=zeros(numel(n),max(n));
    
    % generate data
    for k=[1:1:numel(n)]
        di=2*ones(n(k),1);
        up=-ones(n(k),1);
        lo=-ones(n(k),1);
        b=ones(n(k),1)/(n(k)*n(k)); 
        [subl,du,supu]=tridiag_factor(lo,di,up);
        us_ol0 = tridiag_solve(subl,du,supu,b);
        us_ol(k,[1:numel(us_ol0)])=us_ol0;
    end 
    
    n_us_ol=[1:1:size(us_ol,2)];
    
    str1=['tridiag ' num2str(n(1))];
    str2=['tridiag ' num2str(n(2))];
    legend(str1,str2);
    grid on
    
    % the jacobi traces
    
    nstp=1e3;
    tol=1e-6;
    
    A1=zeros(max(n),max(n),numel(n));
    
    for k=1:1:numel(n)
        A0=full(gallery('tridiag', n(k), -1, 2, -1));
        A1([1:1:size(A0,1)],[1:1:size(A0,2)],k)=A0;
    end
    
    b_A1=ones(max(n),max(n),numel(n));
    
    for k=1:1:numel(n)
    
    for i=1:n(k)
        b_A1(i,1,k)=0.0004;
    end 
    
    end
     
    n_A1=[1:1:size(A1,1)];
    
    jkb=zeros(numel(n),max(n));
    
    for k=1:1:numel(n)
        A0=A1([1:n(k)],[1:n(k)],k);
        b_A0=b_A1([1:n(k)],[1:n(k)],k);
        n0=[1:1:n(k)];
        jkb0=jacobi(A0,b_A0,n0',tol,nstp)
        jkb(k,[1:numel(jkb0)])=jkb0';
    end
    
    % plot data
    figure(1)
    ax1=gca
    plot(ax1,n_us_ol,us_ol(1,:),n_us_ol,us_ol(2,:));
    hold(ax1,'on')
    plot(ax1,n_A1,jkb(1,:),n_A1,jkb(2,:))
    
    grid on
    legend('3/1','3/2','jkb1','jkb2')
    title('3diags and jakobians graph')
    

    enter image description here

    As mentioned above, one has to zoom to find some of the traces

    enter image description here

    One way to combine really small traces with large traces is to use Y log scale

    figure(2)
    ax2=gca
    plot(ax2,n_us_ol,10*log10(us_ol(1,:)),n_us_ol,10*log10(us_ol(2,:)));
    hold(ax2,'on')
    plot(ax2,n_A1,10*log10(jkb(1,:)),n_A1,10*log10(jkb(2,:)))
    
    grid on
    legend('3/1[dB]','3/2[dB]','jkb1[dB]','jkb2[dB]')
    title('3diags and jakobians graph in dB')
    

    enter image description here