X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?p=CreaPhase.git;a=blobdiff_plain;f=octave_packages%2Flinear-algebra-2.2.0%2F%40blksparse%2Fmldivide.m;fp=octave_packages%2Flinear-algebra-2.2.0%2F%40blksparse%2Fmldivide.m;h=3733aab008aeab5715000aafbe552976f4e9b342;hp=0000000000000000000000000000000000000000;hb=f5f7a74bd8a4900f0b797da6783be80e11a68d86;hpb=1705066eceaaea976f010f669ce8e972f3734b05 diff --git a/octave_packages/linear-algebra-2.2.0/@blksparse/mldivide.m b/octave_packages/linear-algebra-2.2.0/@blksparse/mldivide.m new file mode 100644 index 0000000..3733aab --- /dev/null +++ b/octave_packages/linear-algebra-2.2.0/@blksparse/mldivide.m @@ -0,0 +1,115 @@ +## Copyright (C) 2010 VZLU Prague +## +## This program 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. +## +## This program 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 +## . + +## -*- texinfo -*- +## @deftypefn {Function File} mldivide (@var{x}, @var{y}) +## Performs a left division with a block sparse matrix. +## If @var{x} is a block sparse matrix, it must be either diagonal +## or triangular, and @var{y} must be full. +## If @var{x} is built-in sparse or full, @var{y} is converted +## accordingly, then the built-in division is used. +## @end deftypefn + +function c = mldivide (a, b) + if (isa (a, "blksparse")) + if (issparse (b)) + error ("blksparse: block sparse \\ sparse not implemented"); + else + c = mldivide_sm (a, b); + endif + elseif (issparse (a)) + c = a \ sparse (b); + else + c = a \ full (b); + endif +endfunction + +function y = mldivide_sm (s, x) + siz = s.siz; + bsiz = s.bsiz; + if (bsiz(1) != bsiz(2) || siz(1) != siz(2)) + error ("blksparse: can only divide by square matrices with square blocks"); + endif + + ## Check sizes. + [xr, xc] = size (x); + if (xr != siz(1)*bsiz(1)) + gripe_nonconformant (siz.*bsiz, [xr, xc]); + endif + + if (isempty (s) || isempty (x)) + y = x; + return; + endif + + ## Form blocks. + x = reshape (x, bsiz(1), siz(1), xc); + x = permute (x, [1, 3, 2]); + + sv = s.sv; + si = s.i; + sj = s.j; + ns = size (sv, 3); + + n = siz(1); + nb = bsiz(1); + d = find (si == sj); + full_diag = length (d) == n; + + isdiag = full_diag && ns == n; # block diagonal + islower = full_diag && all (si >= sj); # block upper triangular + isupper = full_diag && all (si <= sj); # block lower triangular + + if (isdiag) + xx = num2cell (x, [1, 2]); + ss = num2cell (sv, [1, 2]); + yy = cellfun (@mldivide, ss, xx, "uniformoutput", false); + y = cat (3, yy{:}); + clear xx ss yy; + elseif (islower) + y = x; + ## this is the axpy version + for j = 1:n-1 + y(:,:,j) = sv(:,:,d(j)) \ y(:,:,j); + k = d(j)+1:d(j+1)-1; + xy = y(:,:,j*ones (1, length (k))); + y(:,:,si(k)) -= blkmm (sv(:,:,k), xy); + endfor + y(:,:,n) = sv(:,:,ns) \ y(:,:,n); + elseif (isupper) + y = x; + ## this is the axpy version + for j = n:-1:2 + y(:,:,j) = sv(:,:,d(j)) \ y(:,:,j); + k = d(j-1)+1:d(j)-1; + xy = y(:,:,j*ones (1, length (k))); + y(:,:,si(k)) -= blkmm (sv(:,:,k), xy); + endfor + y(:,:,1) = sv(:,:,1) \ y(:,:,1); + else + error ("blksparse: mldivide: matrix must be block triangular or diagonal"); + endif + + ## Narrow blocks. + y = permute (y, [1, 3, 2]); + y = reshape (y, bsiz(1)*siz(1), xc); +endfunction + +function gripe_nonconformant (s1, s2, what = "arguments") + error ("Octave:nonconformant-args", ... + "nonconformant %s (op1 is %dx%d, op2 is %dx%d)", what, s1, s2); +endfunction +