2012-09-11 26 views
1

我在将伪代码转换为MatLab算法时遇到了一些困难。具体来说,我不知道该怎么做。我会写的伪代码最多的地方我不清楚这一点:Jacobi方法的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

你可以做一个明确的指标阵列和删除索引你不需要

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

太棒了!非常感谢你的帮助!我真的很感激它。 – Kristian

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)); 

所以,现在我们可以写一个单一的雅可比迭代,因为

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更好的起始值。最后,我想提供更完整的帮助和参考。

你想看到的是良好代码的一般特性。

+0

哇,非常感谢!这真的很有帮助。我仍然是MatLab新手,参加我的第一个数值分析课程。我以前只有一些Java的经验,所以我的想法仍然如你所说,更多地围绕低级语言。此外,本书中的所有算法和课堂作业都鼓励我们解决这样的问题。我想重点是,我们应该了解这些细节,然后才能继续讨论更优雅的功能。不过,我非常感谢!我理解你所有的步骤:) – Kristian

+0

(不要指望我经常这样做。)但重点是模拟我提供的代码。使用错误检查。有很多评论可以解释你在做什么。返回那些有用的信息。并且以有效的方式完成所有操作,这样可以避免矩阵操作足以满足的深层嵌套循环。 – 2012-09-11 22:13:21

+0

是的,我不经常指望这种帮助:)。我同意你关于错误检查和评论的意见,并且我总是将这些内容包括在需要交付的作业中,或者当我正在进行更详细的编码时。但是,当我只是将简单的伪算法从我的教科书转换成MatLab时,我只是为了私人用途而采取了一些捷径。不过,我一定会接受你的建议和提示!再次,我真的很感谢你的努力。 – Kristian