Factorización LU#

format long
fmt = format
warning: using the gnuplot graphics toolkit is discouraged

The gnuplot graphics toolkit is not actively maintained and has a number
of limitations that are unlikely to be fixed.  Communication with gnuplot
uses a one-directional pipe and limited information is passed back to the
Octave interpreter so most changes made interactively in the plot window
will not be reflected in the graphics properties managed by Octave.  For
example, if the plot window is closed with a mouse click, Octave will not
be notified and will not update its internal list of open figure windows.
The qt toolkit is recommended instead.
fmt = long
printf('Octave version: %s.', version)
Octave version: 9.1.0.

LUFactSimple.m#

function [L, U, err] = LUFactSimple(A)
    % LU factorization of a square matrix.
    %
    % Input
    %   A(1:n,1:n) : the matrix to be factorized
    %
    % Output
    %   L(1:n,1:n), U(1:n,1:n) : the factors in A = LU, if Gaussian
    %                            elimination proceeds to completion
    %   err : = 0 if Gaussian elimination proceeds to completion
    %         = 1 if a zero pivot is encountered
    n = size(A, 1);
    U = A;
    L = eye(n);
    err = 0;

    for k = 1:n - 1

        for j = k + 1:n

            if abs(U(k, k)) > eps(U(k, k))
                L(j, k) = U(j, k) / U(k, k);
            else
                err = 1;
                return;
            end

            for t = k:n
                U(j, t) = U(j, t) - L(j, k) * U(k, t);
            end

        end

    end

end

Prueba de LUFactSimple.m#

clearvars

n = 3;
A = rand(n, n)

tic
[L, U, err] = LUFactSimple(A)
toc

L * U
A =

   0.180410419500211   0.224341716470787   0.101449379297359
   0.681066884770393   0.271073279923097   0.747127494468375
   0.947437255029046   0.645668259768920   0.897827760160164
L =

   1.000000000000000                   0                   0
   3.775097284608863   1.000000000000000                   0
   5.251566165932764   0.924698652781662   1.000000000000000

U =

   0.180410419500211   0.224341716470787   0.101449379297359
                   0  -0.575838524750263   0.364146218157659
                   0                   0   0.028334114941347

err = 0
Elapsed time is 1.01985 seconds.
ans =

   0.180410419500211   0.224341716470787   0.101449379297359
   0.681066884770393   0.271073279923097   0.747127494468375
   0.947437255029046   0.645668259768920   0.897827760160164

TriDiagonal.m#

function [x, err] = TriDiagonal(a, b, c, f)
    % Solution of a linear system of equations with a tridiagonal
    % matrix.
    %
    %   a(k) x(k-1) + b(k) x(k) + c(k) x(k+1) = f(k)
    %
    % with a(1) = c(n) = 0.
    %
    % Input
    %   a(1:n), b(1:n), c(1:n) : the coefficients of the system
    %                            matrix
    %   f(1:n) : the right hand side vector
    %
    % Output
    %   x(1:n) : the solution to the linear system of equations, if
    %            no division by zero occurs
    %   err : = 0, if no division by zero occurs
    %         = 1, if division by zero is encountered
    n = length(f);
    alpha = zeros(n, 1);
    beta = zeros(n, 1);
    err = 0;

    if abs(b(1)) > eps(b(1))
        alpha(1) = -c(1) / b(1);
        beta(1) = f(1) / b(1);
    else
        err = 1;
        return;
    end

    for k = 2:n
        denominator = a(k) * alpha(k - 1) + b(k);

        if abs(denominator) > eps(denominator)
            alpha(k) =- c(k) / denominator;
            beta(k) = (f(k) - a(k) * beta(k - 1)) / denominator;
        else
            err = 1;
            return;
        end

    end

    if abs(a(n) * alpha(n - 1) + b(n)) > eps(b(n))
        x(n) = (f(n) - a(n) * beta(n - 1)) / (a(n) * alpha(n - 1) + b(n));
    else
        err = 1;
        return;
    end

    for k = n - 1:-1:1
        x(k) = alpha(k) * x(k + 1) + beta(k);
    end

end

Prueba de TriDiagonal.m#

clearvars

n = 5;
a = rand(n, 1)
b = rand(n, 1)
c = rand(n, 1)
f = rand(n, 1)

tic
[x, err] = TriDiagonal(a, b, c, f)
toc

lhs = @(k) a(k) * x(k - 1) + b(k) * x(k) + c(k) * x(k + 1);
rhs = @(k) f(k);

printf('k \t lhs(k) \t rhs(k)\n')
for k=2:n-1
    printf('k = %d\t%f\t%f\n', k, lhs(k), rhs(k))
end
a =

   5.190900154323299e-01
   7.015485663290333e-02
   7.680906530740392e-01
   2.296632816662104e-01
   8.611027785182878e-01
b =

   0.135650021055739
   0.385678086499345
   0.930896574152246
   0.429490435313398
   0.417994154478562
c =

   0.481433364216400
   0.369132687352825
   0.391021583338371
   0.254886212183741
   0.838640087272484
f =

   0.633109112276637
   0.449677053795114
   0.690511626181794
   0.418507575180630
   0.205226954598441
x =

 Columns 1 through 3:

  -5.507820233026685e+01   1.683403980794051e+01  -5.902592465957056e+00

 Columns 4 and 5:

  -1.724931355710016e+01   3.602600329407923e+01

err = 0
Elapsed time is 1.01978 seconds.
k 	 lhs(k) 	 rhs(k)
k = 2	0.449677	0.449677
k = 3	0.690512	0.690512
k = 4	0.418508	0.418508

CyclicallyTriDiagonal.m#

function [x, err] = CyclicallyTriDiagonal(a, b, c, f)
    % Solution of a cyclically tridiagonal linear system of equations:
    %
    %   b(1) x(  1) + c(1) x(  2) + a(1) x(  n) = f(1),
    %   a(k) x(k-1) + b(k) x(  k) + c(k) x(k+1) = f(k),
    %   c(n) x(  1) + a(n) x(n-1) + b(n) x(  n) = f(n).
    %
    % Input
    %   a(1:n), b(1:n), c(1:n) : the coefficients of the system
    %                            matrix
    %   f(1:n) : the right hand side vector
    %
    % Output
    %   x(1:n) : the solution to the linear system of equations, if
    %            no division by zero is encountered
    %   err : = 0, if division by zero does not occur
    %         = 1, if division by zero occurs
    n = length(f);
    err = 0;
    newa = a(2:n);
    newa(1) = 0;
    newb = b(2:n);
    newc = c(2:n);
    newc(n - 1) = 0;
    newf = f(2:n);
    [u, err] = TriDiagonal(newa, newb, newc, newf);

    if err == 1
        return;
    end

    newf = zeros(n - 1, 1);
    newf(1) =- a(2);
    newf(n - 1) = -c(n);
    [v, err] = TriDiagonal(newa, newb, newc, newf);

    if err == 1
        return;
    end

    x = zeros(n, 1);
    denominator = b(1) + c(1) * v(1) + a(1) * v(n - 1);

    if abs(denominator) > eps(denominator)
        x(1) = (f(1) - c(1) * u(1) - a(1) * u(n - 1)) / denominator;
    else
        err = 1;
        return;
    end

    for k = 2:n
        x(k) = u(k - 1) + x(1) * v(k - 1);
    end

end

Prueba de CyclicallyTriDiagonal.m#

clearvars

n = 5;
a = rand(n, 1)
b = rand(n, 1)
c = rand(n, 1)
f = rand(n, 1)

tic
[x, err] = CyclicallyTriDiagonal(a, b, c, f)
toc

lhs = @(k) a(k) * x(k - 1) + b(k) * x(k) + c(k) * x(k + 1);
rhs = @(k) f(k);

printf('k \t lhs(k) \t rhs(k)\n')
for k=2:n-1
    printf('k = %d\t%f\t%f\n', k, lhs(k), rhs(k))
end
a =

   0.994922875798857
   0.546348650244543
   0.177979837790046
   0.503483593329326
   0.816705345802433
b =

   7.866691507468093e-02
   4.012236119204076e-01
   2.661330928485295e-02
   1.775326498797364e-01
   3.655123349684792e-01
c =

   1.913542320563613e-01
   3.694490042524899e-01
   5.012223555645414e-01
   1.455424413559246e-01
   7.844040061393354e-02
f =

   0.481998773759005
   0.361029494105122
   0.646435105394834
   0.937804084591927
   0.889149543980786
x =

  -0.777796629719652
   0.671938132965005
   1.397703559295639
   0.976904048545877
   0.416723185119980

err = 0
Elapsed time is 1.02028 seconds.
k 	 lhs(k) 	 rhs(k)
k = 2	0.361029	0.361029
k = 3	0.646435	0.646435
k = 4	0.937804	0.937804

LUFactEfficient.m#

function [Afact, swaps, err] = LUFactEfficient(A)
    % Efficient implementation of LU factorization with partial
    % pivoting.
    %
    % Input
    %   A(1:n,1:n) : the matrix to be factorized into A = P'LU
    %
    % Output
    %   Afact(1:n,1:n) : a matrix containing the matrices L and U
    %                    below and above the diagonal, respectively
    %   swaps : the indices that indicate the permutations
    %           (row swaps)
    %   err : = 0 if no the factorization finished successfully
    %         = 1 if a division by zero was encountered
    n = size(A, 1);
    swaps = 1:n;
    err = 0;

    for k = 1:n - 1
        i = k;

        for t = k:n

            if abs(A(t, k)) > abs(A(i, k))
                i = t;
            end

        end

        tt = swaps(k);
        swaps(k) = swaps(i);
        swaps(i) = tt;

        if abs(A(swaps(k), k)) <= eps(A(swaps(k), k))
            err = 1;
            return;
        end

        for i = k + 1:n
            xmult = A(swaps(i), k) / A(swaps(k), k);
            A(swaps(i), k) = xmult;

            for j = k + 1:n
                A(swaps(i), j) = A(swaps(i), j) - xmult * A(swaps(k), j);
            end

        end

    end

    Afact = A;
end

Prueba de LUFactEfficient.m#

clearvars

n = 3;
A = rand(n, n)

tic
[Afact, swaps, err] = LUFactEfficient(A)
toc
A =

   5.354339928600693e-01   1.181666427160966e-02   6.556479993425937e-01
   2.134985312932789e-01   2.332058611025711e-02   1.599254811493648e-01
   4.649105358541434e-01   8.878330017306825e-01   6.909137354845939e-01
Afact =

   5.354339928600693e-01   1.181666427160966e-02   6.556479993425937e-01
   3.987392174203530e-01   2.120487311289858e-02  -1.040860872703211e-01
   8.682872997487171e-01   8.775727422182493e-01   1.216229045497647e-01

swaps =

   1   3   2

err = 0
Elapsed time is 1.02017 seconds.

CholeskyDecomposition.m#

function [R, err] = CholeskyDecomposition(A)
    % Choleksy factorization of the HPD matrix A:
    %   A = R'*R
    %
    % Input:
    %   A(1:n,1:n) : an HPD matrix
    %
    % Output:
    %   R(1:n,1:n) : The upper triangular matrix satisfying A = R'*R
    %   err : = 0 if the decomposition finished successfully
    %         = 1 if an error occurred
    err = 0;
    n = size(A, 1);
    R = zeros(n, n);
    R(1, 1) = sqrt(A(1, 1));

    for i = 2:n

        for j = 1:i - 1
            sum = A(i, j);

            for k = 1:j - 1
                sum = sum - R(k, i) * conj(R(k, j));
            end

            if abs(R(j, j)) > eps(R(j, j))
                R(j, i) = sum / R(j, j);
            else
                err = 1;
                return;
            end

        end

        sum = A(i, i);

        for k = 1:i - 1
            sum = sum - R(k, i) * conj(R(k, i));
        end

        R(i, i) = sqrt(sum);
    end

end

Prueba de CholeskyDecomposition.m#

clearvars

A = [1 1/2; 1/2 1]

tic
[R, err] = CholeskyDecomposition(A)
toc

R' * R
A =

   1.000000000000000   0.500000000000000
   0.500000000000000   1.000000000000000
R =

   1.000000000000000   0.500000000000000
                   0   0.866025403784439

err = 0
Elapsed time is 1.01975 seconds.
ans =

   1.000000000000000   0.500000000000000
   0.500000000000000   1.000000000000000

Solve.m#

function [x, err] = Solve(A, f)
    % Solves the system Ax = f.
    %
    % Input
    %   A(1:n,1:n) : the coefficient matrix
    %   f(1:n) : the RHS vector
    %
    % Output:
    %   x(1:n) : the solution vector
    %   err : = 0 if the solution was found successfully
    %         = 1 if an error occurred during the process
    n = length(f);
    err = 0;
    [AA, swaps, err] = LUFactEfficient(A);

    if err == 1
        return
    end

    for k = 1:n - 1

        for i = k + 1:n
            f(swaps(i)) = f(swaps(i)) - AA(swaps(i), k) ...
                *f(swaps(k));
        end

    end

    if abs(AA(swaps(n), n)) > eps(AA(swaps(n), n))
        x(n) = f(swaps(n)) / AA(swaps(n), n);
    else
        err = 1;
        return;
    end

    for i = n - 1:-1:1
        xsum = f(swaps(i));

        for j = i + 1:n
            xsum = xsum - AA(swaps(i), j) * x(j);
        end

        if abs(AA(swaps(i), i)) > eps(AA(swaps(i), i))
            x(i) = xsum / AA(swaps(i), i);
        else
            err = 1;
            return;
        end

    end

end

Prueba de Solve.m#

n = 10
A = rand(n, n);
f = rand(n, 1)

tic
[x, err] = Solve(A, f)
toc

A * x'
n = 10
f =

   3.917672960586684e-01
   9.370306322946349e-01
   1.262360299890020e-01
   8.792291497767564e-01
   7.539948459868598e-01
   1.572338968638454e-02
   9.100074826828775e-02
   6.306062946539864e-01
   9.160734040589031e-01
   9.394105707293133e-01
x =

 Columns 1 through 3:

   0.345304046709965   0.443695225859445  -0.507124860287545

 Columns 4 through 6:

   0.319498371625244  -0.461587550737034   0.452225343631443

 Columns 7 through 9:

   1.050964176714675  -0.208399561579305  -0.227501064451041

 Column 10:

  -0.358390153448041

err = 0
Elapsed time is 1.0227 seconds.
ans =

   3.917672960586683e-01
   9.370306322946350e-01
   1.262360299890022e-01
   8.792291497767565e-01
   7.539948459868596e-01
   1.572338968638456e-02
   9.100074826828769e-02
   6.306062946539864e-01
   9.160734040589033e-01
   9.394105707293132e-01