Mercurial > octave-nkf
view scripts/sparse/ilu.m @ 19088:df64071e538c
Removed ichol0.cc, icholt.cc, ilu0.cc, iluc.cc, ilutp.cc. Created __ichol__.cc and __ilu__.cc. Minor bugs fixed.
* libinterp/dldfcn/__ichol__.cc: File created now contains __ichol0__ and __icholt__ functions.
* libinterp/dldfcn/__ilu__.cc: File created now contains __ilu0__ __iluc__ and __ilutp__ functions.
* scripts/sparse/ichol.m: Tests have been moved from .cc files to this one.
* changed scripts/sparse/ilu.m: Tests have been moved from .cc files to this one.
author | Eduardo Ramos (edu159) <eduradical951@gmail.com> |
---|---|
date | Mon, 18 Aug 2014 12:32:16 +0100 |
parents | 168c0aa9bb05 |
children | 38937efbee21 |
line wrap: on
line source
## Copyright (C) 2013 Kai T. Ohlhus <k.ohlhus@gmail.com> ## Copyright (C) 2014 Eduardo Ramos Fernández <eduradical951@gmail.com> ## ## ## This file is part of Octave. ## ## Octave is free software; you can redistribute it and/or modify it under the ## terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## Octave is distributed in the hope that it will be useful, but WITHOUT ANY ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. ## -*- texinfo -*- ## @deftypefn {Function File} ilu (@var{A}, @var{setup}) ## @deftypefnx {Function File} {[@var{L}, @var{U}] =} ilu (@var{A}, @var{setup}) ## @deftypefnx {Function File} {[@var{L}, @var{U}, @var{P}] =} ilu (@var{A}, @var{setup}) ## ilu produces a unit lower triangular matrix, an upper triangular matrix, and ## a permutation matrix. ## ## These incomplete factorizations may be useful as preconditioners for a system ## of linear equations being solved by iterative methods such as BICG ## (BiConjugate Gradients), GMRES (Generalized Minimum Residual Method). ## ## @code{ilu (@var{A}, @var{setup})} computes the incomplete LU factorization ## of @var{A}. @var{setup} is an input structure with up to five setup options. ## The fields must be named exactly as shown below. You can include any number ## of these fields in the structure and define them in any order. Any ## additional fields are ignored. ## ## @table @asis ## @item type ## Type of factorization. Values for type include: ## ## @table @asis ## @item @samp{nofill} ## Performs ILU factorization with 0 level of fill in, known as ILU(0). With ## type set to @samp{nofill}, only the milu setup option is used; all other ## fields are ignored. ## @item @samp{crout} ## Performs the Crout version of ILU factorization, known as ILUC. With type ## set to @samp{crout}, only the droptol and milu setup options are used; all ## other fields are ignored. ## @item @samp{ilutp} ## (default) Performs ILU factorization with threshold and pivoting. ## @end table ## ## If type is not specified, the ILU factorization with pivoting ILUTP is ## performed. Pivoting is never performed with type set to @samp{nofill} or ## @samp{crout}. ## ## @item droptol ## Drop tolerance of the incomplete LU factorization. droptol is a non-negative ## scalar. The default value is 0, which produces the complete LU factorization. ## ## The nonzero entries of U satisfy ## ## @code{abs (@var{U}(i,j)) >= droptol * norm ((@var{A}:,j))} ## ## with the exception of the diagonal entries, which are retained regardless of ## satisfying the criterion. The entries of @var{L} are tested against the ## local drop tolerance before being scaled by the pivot, so for nonzeros in ## @var{L} ## ## @code{abs(@var{L}(i,j)) >= droptol * norm(@var{A}(:,j))/@var{U}(j,j)}. ## ## @item milu ## Modified incomplete LU factorization. Values for milu ## include: ## @table @asis ## @item @samp{row} ## Produces the row-sum modified incomplete LU factorization. Entries from the ## newly-formed column of the factors are subtracted from the diagonal of the ## upper triangular factor, @var{U}, preserving column sums. That is, ## @code{@var{A} * e = @var{L} * @var{U} * e}, where e is the vector of ones. ## @item @samp{col} ## Produces the column-sum modified incomplete LU factorization. Entries from ## the newly-formed column of the factors are subtracted from the diagonal of ## the upper triangular factor, @var{U}, preserving column sums. That is, ## @code{e'*@var{A} = e'*@var{L}*@var{U}}. ## @item @samp{off} ## (default) No modified incomplete LU factorization is produced. ## @end table ## ## @item udiag ## If udiag is 1, any zeros on the diagonal of the upper ## triangular factor are replaced by the local drop tolerance. The default is 0. ## ## @item thresh ## Pivot threshold between 0 (forces diagonal pivoting) and 1, ## the default, which always chooses the maximum magnitude entry in the column ## to be the pivot. ## @end table ## ## @code{ilu (@var{A},@var{setup})} returns ## @code{@var{L} + @var{U} - speye (size (@var{A}))}, where @var{L} is a unit ## lower triangular matrix and @var{U} is an upper triangular matrix. ## ## @code{[@var{L}, @var{U}] = ilu (@var{A},@var{setup})} returns a unit lower ## triangular matrix in @var{L} and an upper triangular matrix in @var{U}. When ## SETUP.type = 'ilutp', the role of @var{P} is determined by the value of ## SETUP.milu. For SETUP.type == 'ilutp', one of the factors is permuted ## based on the value of SETUP.milu. When SETUP.milu == 'row', U is a column ## permuted upper triangular factor. Otherwise, L is a row-permuted unit lower ## triangular factor. ## ## @code{[@var{L}, @var{U}, @var{P}] = ilu (@var{A},@var{setup})} returns a ## unit lower triangular matrix in @var{L}, an upper triangular matrix in ## @var{U}, and a permutation matrix in @var{P}. When SETUP.milu ~= 'row', @var{P} ## is returned such that @var{L} and @var{U} are incomplete factors of @var{P}*@var{A}. ## When SETUP.milu == 'row', @var{P} is returned such that and @var{U} are ## incomplete factors of A*P. ## ## @strong{NOTE}: ilu works on sparse square matrices only. ## ## EXAMPLES ## ## @example ## A = gallery('neumann', 1600) + speye(1600); ## setup.type = 'nofill'; ## nnz(A) ## ans = 7840 ## ## nnz(lu(A)) ## ans = 126478 ## ## nnz(ilu(A,setup)) ## ans = 7840 ## @end example ## ## This shows that @var{A} has 7840 nonzeros, the complete LU factorization has ## 126478 nonzeros, and the incomplete LU factorization, with 0 level of ## fill-in, has 7840 nonzeros, the same amount as @var{A}. Taken from: ## http://www.mathworks.com/help/matlab/ref/ilu.html ## ## @example ## A = gallery ('wathen', 10, 10); ## b = sum (A,2); ## tol = 1e-8; ## maxit = 50; ## opts.type = 'crout'; ## opts.droptol = 1e-4; ## [L, U] = ilu (A, opts); ## x = bicg (A, b, tol, maxit, L, U); ## norm(A * x - b, inf) ## @end example ## ## This example uses ILU as preconditioner for a random FEM-Matrix, which has a ## bad condition. Without @var{L} and @var{U} BICG would not converge. ## ## @end deftypefn function [L, U, P] = ilu (A, setup) if ((nargin > 2) || (nargin < 1) || (nargout > 3)) print_usage (); endif % Check input matrix if (~issparse (A) || ~issquare (A)) error ("ilu: Input A must be a sparse square matrix."); endif % If A is empty and sparse then return empty L, U and P % Compatibility with Matlab if (isempty (A)) L = A; U = A; P = A; return; endif % Check input structure, otherwise set default values if (nargin == 2) if (~isstruct (setup)) error ("ilu: Input 'setup' must be a valid structure."); endif else setup = struct (); endif if (~isfield (setup, "type")) setup.type = "nofill"; % set default else type = tolower (getfield (setup, "type")); if ((strcmp (type, "nofill") == 0) && (strcmp (type, "crout") == 0) && (strcmp (type, "ilutp") == 0)) error ("ilu: Invalid field \"type\" in input structure."); else setup.type = type; endif endif if (~isfield (setup, "droptol")) setup.droptol = 0; % set default else if (~isscalar (setup.droptol) || (setup.droptol < 0)) error ("ilu: Invalid field \"droptol\" in input structure."); endif endif if (~isfield (setup, "milu")) setup.milu = "off"; % set default else milu = tolower (getfield (setup, "milu")); if ((strcmp (milu, "off") == 0) && (strcmp (milu, "col") == 0) && (strcmp (milu, "row") == 0)) error ("ilu: Invalid field \"milu\" in input structure."); else setup.milu = milu; endif endif if (~isfield (setup, "udiag")) setup.udiag = 0; % set default else if (~isscalar (setup.udiag) || ((setup.udiag ~= 0) && (setup.udiag ~= 1))) error ("ilu: Invalid field \"udiag\" in input structure."); endif endif if (~isfield (setup, "thresh")) setup.thresh = 1; % set default else if (~isscalar (setup.thresh) || (setup.thresh < 0) || (setup.thresh > 1)) error ("ilu: Invalid field \"thresh\" in input structure."); endif endif n = length (A); % Delegate to specialized ILU switch (setup.type) case "nofill" [L, U] = __ilu0__ (A, setup.milu); if (nargout == 3) P = speye (length (A)); endif case "crout" [L, U] = __iluc__ (A, setup.droptol, setup.milu); if (nargout == 3) P = speye (length (A)); endif case "ilutp" if (nargout == 2) [L, U] = __ilutp__ (A, setup.droptol, setup.thresh, setup.milu, setup.udiag); elseif (nargout == 3) [L, U, P] = __ilutp__ (A, setup.droptol, setup.thresh, setup.milu, setup.udiag); endif otherwise printf ("The input structure is invalid.\n"); endswitch if (nargout == 1) L = L + U - speye (n); endif endfunction %!shared n, dtol, A %! n = 1600; %! dtol = 0.1; %! A = gallery ('neumann', n) + speye (n); %!test %! setup.type = 'nofill'; %! assert (nnz (ilu (A, setup)), 7840); %! # This test is taken from the mathworks and should work for full support. %!test %! setup.type = 'crout'; %! setup.milu = 'row'; %! setup.droptol = dtol; %! [L, U] = ilu (A, setup); %! e = ones (size (A, 2),1); %! assert (norm (A*e - L*U*e), 1e-14, 1e-14); %!test %! setup.type = 'crout'; %! setup.droptol = dtol; %! [L, U] = ilu(A, setup); %! assert (norm (A - L * U, 'fro') / norm (A, 'fro'), 0.05, 1e-2); %! # Tests for input validation %!test %! [L, U] = ilu (sparse ([])); %! assert (isempty (L), logical (1)); %! assert (isempty (U), logical (1)); %! setup.type = 'crout'; %! [L, U] = ilu (sparse ([]), setup); %! assert (isempty (L), logical (1)); %! assert (isempty (U), logical (1)); %! setup.type = 'ilutp'; %! [L, U] = ilu (sparse ([]), setup); %! assert (isempty (L), logical (1)); %! assert (isempty (U), logical (1)); %!error [L, U] = ilu (0); %!error [L, U] = ilu ([]); %!error [L, U] = ilu (sparse (0)); %!test %! setup.type = 'foo'; %!error [L, U] = ilu (A_tiny, setup); %! setup.type = 1; %!error [L, U] = ilu (A_tiny, setup); %! setup.type = []; %!error [L, U] = ilu (A_tiny, setup); %!test %! setup.droptol = -1; %!error [L, U] = ilu (A_tiny, setup); %! setup.droptol = 0.5i; %!error [L, U] = ilu (A_tiny, setup); %! setup.droptol = []; %!error [L, U] = ilu (A_tiny, setup); %!test %! setup.thresh= -1; %!error [L, U] = ilu (A_tiny, setup); %! setup.thresh = 0.5i; %!error [L, U] = ilu (A_tiny, setup); %! setup.thresh = []; %!error [L, U] = ilu (A_tiny, setup); %! setup.thresh = 2; %!error [L, U] = ilu (A_tiny, setup); %!test %! setup.diag = 0.5; %!error [L, U] = ilu (A_tiny, setup); %! setup.diag = []; %!error [L, U] = ilu (A_tiny, setup); %! setup.diag = -1; %!error [L, U] = ilu (A_tiny, setup); %!test %! setup.milu = 'foo'; %!error [L, U] = ilu (A_tiny, setup); %! setup.milu = 1; %!error [L, U] = ilu (A_tiny, setup); %! setup.milu = []; %!error [L, U] = ilu (A_tiny, setup); %! # Check if the elements in U satisfy the non-dropping condition. %!test %! setup.type = 'crout'; %! setup.droptol = dtol; %! [L, U] = ilu (A, setup); %! for j = 1:n %! cmp_value = dtol * norm (A(:, j)); %! non_zeros = nonzeros (U(:, j)); %! for i = 1:length (non_zeros); %! assert (abs (non_zeros (i)) >= cmp_value, logical (1)); %! endfor %! endfor %!test %! setup.type = 'ilutp'; %! setup.droptol = dtol; %! [L, U] = ilu (A, setup); %! for j = 1:n %! cmp_value = dtol * norm (A(:, j)); %! non_zeros = nonzeros (U(:, j)); %! for i = 1:length (non_zeros); %! assert (abs (non_zeros (i)) >= cmp_value, logical (1)); %! endfor %! endfor %! # Check that the complete LU factorisation with crout and ilutp algorithms %! # output the same result. %!test %! setup.type = 'crout'; %! setup.droptol = 0; %! [L1, U1] = ilu (A, setup); %! setup.type = 'ilutp'; %! setup.thresh = 0; %! [L2, U2] = ilu (A, setup); %! assert (norm (L1 - L2, 'fro') / norm (L1, 'fro'), 0, eps); %! assert (norm (U1 - U2, 'fro') / norm (U1, 'fro'), 0, eps); %! # Tests for real matrices of different sizes for ilu0, iluc and ilutp. %! # The difference A - L*U should be not greater than eps because with droptol %! # equaling 0, the LU complete factorization is performed. %!shared n_tiny, n_small, n_medium, n_large, A_tiny, A_small, A_medium, A_large %! n_tiny = 5; %! n_small = 40; %! n_medium = 600; %! n_large = 10000; %! A_tiny = spconvert ([1 4 2 3 3 4 2 5; 1 1 2 3 4 4 5 5; 1 2 3 4 5 6 7 8]'); %! A_small = sprand (n_small, n_small, 1/n_small) + speye (n_small); %! A_medium = sprand (n_medium, n_medium, 1/n_medium) + speye (n_medium); %! A_large = sprand (n_large, n_large, 1/n_large/10) + speye (n_large); %! %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_tiny); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), 0, n_tiny * eps); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_small); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), 0, 1); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_medium); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), 0, 1); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_large); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), 0, 1); %! %!test %! setup.type = "crout"; %! [L, U] = ilu (A_tiny, setup); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_small, setup); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_medium, setup); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_large, setup); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), eps, eps); %! %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_tiny, setup); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_small, setup); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_medium, setup); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_large, setup); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), eps, eps); %! %! # Tests for complex matrices of different sizes for ilu0, iluc and ilutp. %!shared n_tiny, n_small, n_medium, n_large, A_tiny, A_small, A_medium, A_large %! n_tiny = 5; %! n_small = 40; %! n_medium = 600; %! n_large = 10000; %! A_tiny = spconvert ([1 4 2 3 3 4 2 5; 1 1 2 3 4 4 5 5; 1 2 3 4 5 6 7 8]'); %! A_tiny(1,1) += 1i; %! A_small = sprand(n_small, n_small, 1/n_small) + ... %! i * sprand(n_small, n_small, 1/n_small) + speye (n_small); %! A_medium = sprand(n_medium, n_medium, 1/n_medium) + ... %! i * sprand(n_medium, n_medium, 1/n_medium) + speye (n_medium); %! A_large = sprand(n_large, n_large, 1/n_large/10) + ... %! i * sprand(n_large, n_large, 1/n_large/10) + speye (n_large); %! %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_tiny); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), 0, n_tiny * eps); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_small); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), 0, 1); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_medium); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), 0, 1); %!test %! setup.type = "nofill"; %! [L, U] = ilu (A_large); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), 0, 1); %! %!test %! setup.type = "crout"; %! [L, U] = ilu (A_tiny, setup); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_small, setup); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_medium, setup); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), eps, eps); %!test %! setup.type = "crout"; %! [L, U] = ilu (A_large, setup); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), eps, eps); %! %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_tiny, setup); %! assert (norm (A_tiny - L * U, "fro") / norm (A_tiny, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_small, setup); %! assert (norm (A_small - L * U, "fro") / norm (A_small, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_medium, setup); %! assert (norm (A_medium - L * U, "fro") / norm (A_medium, "fro"), eps, eps); %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! [L, U] = ilu (A_large, setup); %! assert (norm (A_large - L * U, "fro") / norm (A_large, "fro"), eps, eps); %! #Specific tests for ilutp %!shared a1, a2 %! a1 = sparse ([0 0 4 3 1; 5 1 2.3 2 4.5; 0 0 0 2 1;0 0 8 0 2.2; 0 0 9 9 1 ]); %! a2 = sparse ([3 1 0 0 4; 3 1 0 0 -2;0 0 8 0 0; 0 4 0 4 -4.5; 0 -1 0 0 1]); %!test %! setup.udiag = 1; %! setup.type = "ilutp"; %! setup.droptol = 0.2; %! [L, U, P] = ilu (a1, setup); %! assert (norm (U, "fro"), 17.4577, 1e-4); %! assert (norm (L, "fro"), 2.4192, 1e-4); %! setup.udiag = 0; %!error [L, U, P] = ilu (a1, setup); %! %!test %! setup.type = "ilutp"; %! setup.droptol = 0; %! setup.thresh = 0; %! setup.milu = "row"; %!error [L, U] = ilu (a2, setup); %!