Jacobi方法的MatLab算法

时间:2012-09-11 19:36:08

标签: matlab sum

我在将伪代码转换为MatLab算法时遇到了一些困难。具体来说,有一部分我不太清楚该怎么做。我会把伪代码写到我不确定的地步:

 input n, (a_{ij}), (b_i), (x_i), M
    for k = 1 to M do
       for i = 1 to n do

           u_i = (b_i - sum[(from j = 1, (j ≠ i), to n) a_{ij} * x_j]) / a_{ii}
       end do

我遇到的困难是我必须编写总和部分。我无法弄清楚的是如何编写算法,以便不包括j≠i的项。到目前为止,我写了:

function [k,x] = jacobimethod(A,b,M)
n = length(A);
u = zeros(1,n);
x = zeros(1,n);
for k = 1:M
    for i = 1:n
        u(i) = (b(i) - (A(i

这就是我被困的地方。到目前为止,我的所有算法都涉及所有项都应包含的和,即使是j = i的那些项。在这种情况下,和项只是:

A(i,1:n)*x(1:n)'

但是如何修改它以便不包含A(i,i)

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:4)

既然你已经提供了代码,那就付出了努力......我会指出一个更好的方法。使用MATLAB时,请尝试使用该语言的功能。不要假装你还在使用低级语言。因此,我们可以将jacobi迭代编写为

X_(n+1) = inv(D)*(b - R*X_n)

其中D是包含A的对角线的对角矩阵,R是A的非对角线元素的矩阵,因此对角线上有零。我们怎样才能在MATLAB中做到这一点?

首先,以简单的方式构建D和R.

D = diag(diag(A));
R = A - D;

现在,我们应该认识到计算对角矩阵的逆是愚蠢的。更好的是计算对角线上每个元素的倒数。

Dinv = diag(1./diag(A));

所以,现在我们可以编写一个Jacobi迭代,如

X = Dinv*(b - R*X);

请注意,不需要嵌套循环。我们根本不打算索引这些矩阵。现在将它全部包含在MATLAB函数中。要友好,检查问题,并大量使用评论。

=============================================== ===

function [X,residuals,iter] = JacobiMethod(A,b)
% solves a linear system using Jacobi iterations
%
% The presumption is that A is nxn square and has no zeros on the diagonal
% also, A must be diagonally dominant for convergence.
% b must be an nx1 vector.

n = size(A,1);
if n ~= size(A,2)
  error('JACOBIMETHOD:Anotsquare','A must be n by n square matrix')
end
if ~isequal(size(b),[n 1])
  error('JACOBIMETHOD:incompatibleshapes','b must be an n by 1 vector')
end

% get the diagonal elements
D = diag(A);
% test that none are zero
if any(D) == 0
  error('JACOBIMETHOD:zerodiagonal', ...
    'The sky is falling! There are zeros on the diagonal')
end

% since none are zero, we can compute the inverse of D.
% even better is to make Dinv a sparse diagonal matrix,
% for better speed in the multiplies.
Dinv = sparse(diag(1./D));
R = A - diag(D);

% starting values. I'm not being very creative here, but
% using the vector b as a starting value seems reasonable.
X = b;
err = inf;
tol = 100*eps(norm(b));
iter = 0; % count iterations
while err > tol
  iter = iter + 1;
  Xold = X;

  % the guts of the iteration
  X = Dinv*(b - R*X);

  % this is not really an error, but a change per iteration.
  % when that is stable, we choose to terminate.
  err = norm(X - Xold);
end

% compute residuals
residuals = b - A*X;

=============================================== ===

让我们看看它是如何工作的。

A = rand(5) + 4*eye(5);
b = rand(5,1);
[X,res,iter] = JacobiMethod(A,b)

X =
      0.12869
   -0.0021942
      0.10779
      0.11791
      0.11785

res =
   5.7732e-15
   1.6653e-14
   1.5654e-14
   1.6542e-14
    1.843e-14

iter =
    39

它是否收敛于我们从反斜杠得到的解决方案?

A\b
ans =
      0.12869
   -0.0021942
      0.10779
      0.11791
      0.11785

对我来说很好看。更好的代码可能会检查对角线优势,以尝试预测代码何时失败。我可能已经选择了对解决方案更加智能的容忍度,或者X的更好的起始值。最后,我想提供更完整的帮助,包括参考。

您希望看到的是良好代码的一般特征。

答案 1 :(得分:2)

您可以创建一个显式索引数组并删除不需要的索引

% inside of the loop
idx = 1:n;
idx(i) = [];
u(i) = (b(i)-sum(A(i,idx).*x(idx)))/A(i,i);