我已经实现了Jacobi算法,以两种方式迭代求解线性系统。它们都是先检查一下是否可以应用该方法,然后明确地构造迭代矩阵P和迭代'添加了向量c,而另一个使用每个迭代的子函数逐个组件地计算新的向量。这是第一个:
function [x,nit,t,invt] = jacobi(A,b,tol,x0,NMAX)
%Perfetto equivalente di jacobsparse.m che lavora con A in formato full e
%restituisce sia il tempo impiegato a risolvere il sistema sia quello
%impiegato per invertire la matrice D che serve a calcolare la matrice di
%iterazione.
if nargin < 5
NMAX=100;
%Se il max di iterazioni non ? dato, viene automaticamente impostato a
%100.
if nargin < 4
x0=zeros(1,length(A));
%Se l'innesco non ? dato, viene automaticamente impostato al
%vettore nullo.
if nargin < 3
error('Mi devi dare almeno la matrice, il termine noto e la tolleranza')
%Se manca anche la tolleranza, non volendo dare un valore di
%default che non sapevo come sceglierlo, gli faccio dare
%errore.
end
end
end
matsize=size(A);
if matsize(1)~=length(b)
error('Le dimensioni di matrice e termine noto non concordano')
%Se b non ? A per un vettore, allora non posso risolvere il sistema.
end
if matsize(2)~=length(x0)
error('Le dimensioni di matrice e vettore d''innesco non concordano')
%Se A*x0 non ? definito, l'innesco non ha la dimensione giusta per
%poter risolvere il sistema.
end
if matsize(1)~=matsize(2)
error('Non posso applicare il metodo a matrici rettangolari.')
%Il metodo di Jacobi non si pu? applicare a matrici rettangolari perch?
%le componenti delle iterate si ricavano in corrispondenza con quelle
%del termine noto, e se i numeri di componenti di b e di x sono diversi
%non riesco a risolvere il problema.
end
for i=1:min(size(A))
if A(i,i)==0
error('Non posso applicare il metodo causa elemento diagonale (%.0f,%.0f) nullo.',i,i)
%Il metodo richiede di dividere almeno una volta per ogni elemento
%diagonale, quindi se un elemento ? nullo ci fermiamo subito, prima
%che capiti "Division by zero", che poi su MATLAB manco d? errore,
%d? Inf.
end
end
nit=0;
incr=tol;
xold=x0;
%Inizializzo queste variabili in modo da poterle usare subito. nit ?
%ovviamente 0, poi viene incrementato; incr lo metto a tol cos? entra nel
%ciclo; xold parte da x0.
diagon=diag(A,0);
D=diag(diagon);
LU=A-D;
tic
Dinv=inv(D);
invt=toc;
P=Dinv*LU;
c=Dinv*b;
tic
while nit < NMAX && incr >= tol
nit = nit + 1;
%Incremento il numero di iterazioni.
xnew = P*xold+c;
%Ricavo con la subfunction il vettore xnew dell'iterata corrente.
x = xnew;
%Metto xnew in x, cos? se si esce x ? gi? sistemato.
incr = norm(xnew-xold);
%Salvo la norma dell'incremento.
xold=xnew;
%Metto xnew in xold, cosicch? la prossima iterata usi xnew come xold e
%ricavi il corrispondente xnew.
end
t=toc;
end
这是第二个:
function [x,nit,t] = jacobsparse(A,b,tol,x0,NMAX)
%Restituisce la soluzione x del sistema con matrice A e b in ingresso,
%ottenuta col metodo di Jacobi con tolleranza tol in ingresso, innesco x0
%in ingresso o automaticamente nullo, e massimo di iterazioni NMAX in
%ingresso o automaticamente 100. Se non ha abbastanza input, d? errore.
%Lavora con A in formato sparse. L'equivalente in formato full ? jacobi.m.
%Restituisce anche il numero di iterazioni effettivamente compiute nit e il
%tempo impiegato t. Si serve di jac_iter.m per le singole iterazioni del
%metodo.
if nargin < 5
NMAX=100;
%Se il max di iterazioni non ? dato, viene automaticamente impostato a
%100.
if nargin < 4
x0=zeros(length(A),1);
%Se l'innesco non ? dato, viene automaticamente impostato al
%vettore nullo.
if nargin < 3
error('Mi devi dare almeno la matrice, il termine noto e la tolleranza')
%Se manca anche la tolleranza, non volendo dare un valore di
%default che non sapevo come sceglierlo, gli faccio dare
%errore.
end
end
end
matsize=size(A);
if matsize(1)~=length(b)
error('Le dimensioni di matrice e termine noto non concordano')
%Se b non ? A per un vettore, allora non posso risolvere il sistema.
end
if matsize(2)~=length(x0)
error('Le dimensioni di matrice e vettore d''innesco non concordano')
%Se A*x0 non ? definito, l'innesco non ha la dimensione giusta per
%poter risolvere il sistema.
end
if matsize(1)~=matsize(2)
error('Non posso applicare il metodo a matrici rettangolari.')
%Il metodo di Jacobi non si pu? applicare a matrici rettangolari perch?
%le componenti delle iterate si ricavano in corrispondenza con quelle
%del termine noto, e se i numeri di componenti di b e di x sono diversi
%non riesco a risolvere il problema.
end
for i=1:min(size(A))
if A(i,i)==0
error('Non posso applicare il metodo causa elemento diagonale (%.0f,%.0f) nullo.',i,i)
%Il metodo richiede di dividere almeno una volta per ogni elemento
%diagonale, quindi se un elemento ? nullo ci fermiamo subito, prima
%che capiti "Division by zero", che poi su MATLAB manco d? errore,
%d? Inf.
end
end
nit=0;
incr=tol;
xold=x0;
%Inizializzo queste variabili in modo da poterle usare subito. nit ?
%ovviamente 0, poi viene incrementato; incr lo metto a tol cos? entra nel
%ciclo; xold parte da x0.
tic
while nit < NMAX && incr >= tol
nit = nit + 1;
%Incremento il numero di iterazioni.
xnew = jac_iter(A,xold,b);
%Ricavo con la subfunction il vettore xnew dell'iterata corrente.
x = xnew;
%Metto xnew in x, cos? se si esce x ? gi? sistemato.
incr = norm(xnew-xold);
%Salvo la norma dell'incremento.
xold=xnew;
%Metto xnew in xold, cosicch? la prossima iterata usi xnew come xold e
%ricavi il corrispondente xnew.
end
t=toc;
end
具有以下子功能:
function xnew = jac_iter(A,xold,b)
xnew=zeros(length(xold),1);
for i=1:length(xold)
xnew(i)=b(i);
%Comincio a mettere b(i) in xnew(i).
for j=1:i-1
xnew(i) = xnew(i)-A(i,j)*xold(j);
%Poi ci sottraggo la somma per j<i di A(i,j)*xold(j).
end
for j=i+1:length(xold)
xnew(i) = xnew(i)-A(i,j)*xold(j);
%Poi ci sottraggo la somma per j>i.
end
xnew(i)=xnew(i)/A(i,i);
%Infine divido il tutto per A(i,i), cos? divido solo una volta. Il
%ciclo naturalmente va da 1 a size(xold)=size(xnew).
end
end
对于意大利语中的评论感到抱歉,但是我用意大利语写了这些评论,因为这将被放入&#34;报告&#34;在意大利语和英语评论似乎不合适。我想谷歌不应该对这些做得太糟糕。如果您希望我翻译它们,请告诉我。无论如何,我的问题是:为什么第一个,在2000×2000的全格式稀疏矩阵中,需要大约5.4e-1秒来反转对角矩阵和1.8e-1秒来解决系统只有最多200次迭代91次,而200次迭代后的第二次迭代结束其工作耗时1e4秒?这意味着,假设一次迭代的时间是恒定的,那么数字2将花费大约5e3秒来执行数字1在~2s中所做的相同事情!然而,他们应该以不同的顺序或多或少地做同样的操作!为什么1号收敛而2号不收?我在这里错过了什么吗?最后,我被告知要实现两个不同的函数来将这个算法应用于完整和稀疏格式的矩阵,并且我找不到任何明智的理由。有什么想法吗? PS如果你觉得我应该分开问这个问题,请告诉我,我会。
更新 按照迈克尔的建议,我写了下面的代码:
clear all
clc
for i=1:200
[A,A1]=sparsa2(10*i);
tic
xnew=jac_iter(A,zeros(10*i,1),ones(10*i,1));
times(1,i)=toc;
toc
tic
xnew=jac_iter(A1,zeros(10*i,1),ones(10*i,1));
times(2,i)=toc;
toc
tic
diagmat=diag(diag(A1,0));
Dinv=inv(diagmat);
LU=A1-diagmat;
P=Dinv*LU;
c=Dinv*ones(10*i,1);
times(3,i)=toc;
toc
tic
xnew2=P*zeros(10*i,1)+c;
times(4,i)=toc;
toc
end
这使用以下功能:
function [A,A1]=sparsa2(n,dens)
%Crea una matrice n-per-n sparsa con densit? dens tramite sprand; la
%densit? si pu? lasciare automaticamente impostata a 20. La function si
%sincera anche che la diagonale non contenga zeri.
if nargin == 0
error('Almeno la dimensione me la devi dare, se no come ti faccio la matrice sparsa?')
%Se non viene data la dimensione, errore.
elseif nargin == 1
dens = 20;
%Se non viene data la densit?, si imposta automaticamente a 20.
end
A=rand(n);
%Si crea la matrice.
tol=dens/100;
%Si salva la densit? in formato decimale.
for i=1:n
for j=1:n
if A(i,i)<tol && i~=j
A(i,i)=0;
%Si impone una sparsit? con densit? di non zeri dens azzerando
%tutto quello che nella matrice sta sotto a dens/100;
%ovviamente questo si basa sull'euristica che la probabilit? di
%ottenere con rand un numero qualunque sia sempre la stessa e
%evita di azzerare entrate diagonali.
end
end
end
for i=1:n
if A(i,i)==0
A(i,i)=rand;
end
%Visto che questa function devo usarla per fornire matrici a Jacobi, mi
%sincero che sulla diagonale non ci siano zeri, altrimenti Jacobi non
%si pu? applicare. Per ottimizzare i tempi non sostituisco con rand
%tutte le entrate diagonali di A, ma solo quelle nulle, che vengono
%individuate con un condizionale.
end
A1=A;
A=sparse(A);
%Memorizzo in A1 il formato full, che per ora ? quello di A, e poi metto
%in A il formato sparse.
与意大利语中的评论相同。我使用rand
然后归零一些术语因为sprand
,除了没有观察非零的密度要求(第三个参数是非零的密度,而不是零的密度,对吧? ),需要aaaaaages产生一个矩阵,然后它仍然必须非对角线,否则Jacobi算法不能应用。我在运行该代码的过程中受到了厌倦,并在大约i=185
停了下来,获得了以下times'
:
0.0067 0.0033 0.0029 0.0003
0.0075 0.0001 0.0003 0.0001
0.0156 0.0001 0.0552 0.0000
0.0201 0.0001 0.0003 0.0000
0.0409 0.0001 0.0003 0.0000
0.0613 0.0002 0.0004 0.0000
0.0720 0.0003 0.0006 0.0001
0.1075 0.0003 0.0007 0.0001
0.1186 0.0003 0.0009 0.0001
0.1515 0.0004 0.0008 0.0001
0.1915 0.0004 0.0010 0.0001
0.2400 0.0005 0.0015 0.0001
0.2494 0.0006 0.0025 0.0001
0.2902 0.0007 0.0026 0.0001
0.3299 0.0008 0.0026 0.0001
0.3408 0.0008 0.0029 0.0002
0.3995 0.0012 0.0038 0.0002
0.4324 0.0012 0.0039 0.0001
0.4687 0.0014 0.0062 0.0003
0.5365 0.0015 0.0061 0.0003
0.5922 0.0017 0.0072 0.0001
0.6417 0.0019 0.0070 0.0001
0.6970 0.0020 0.0076 0.0001
0.7088 0.0022 0.0082 0.0001
0.8002 0.0027 0.0087 0.0002
0.8338 0.0025 0.0117 0.0004
0.9091 0.0026 0.0105 0.0003
0.9981 0.0033 0.0110 0.0001
1.0528 0.0034 0.0121 0.0001
1.1499 0.0038 0.0117 0.0002
1.1778 0.0038 0.0143 0.0001
1.2721 0.0042 0.0156 0.0002
1.3673 0.0046 0.0182 0.0002
1.4727 0.0045 0.0183 0.0002
1.5056 0.0049 0.0211 0.0003
1.6287 0.0052 0.0214 0.0003
1.6792 0.0057 0.0163 0.0002
1.7923 0.0061 0.0226 0.0002
1.8907 0.0062 0.0220 0.0002
2.0210 0.0067 0.0227 0.0002
2.0612 0.0071 0.0281 0.0003
2.1789 0.0076 0.0290 0.0003
2.3028 0.0076 0.0274 0.0002
2.3854 0.0079 0.0253 0.0002
2.5192 0.0088 0.0326 0.0003
2.6105 0.0089 0.0314 0.0003
2.7601 0.0093 0.0375 0.0012
2.9112 0.0094 0.0340 0.0002
3.0224 0.0106 0.0350 0.0002
3.1576 0.0108 0.0420 0.0003
3.2817 0.0107 0.0357 0.0004
3.4132 0.0112 0.0392 0.0003
3.5205 0.0118 0.0505 0.0004
3.6826 0.0122 0.0432 0.0003
3.8778 0.0134 0.0581 0.0005
4.0303 0.0135 0.0499 0.0003
4.1311 0.0147 0.0496 0.0003
4.2592 0.0148 0.0583 0.0004
4.4248 0.0149 0.0625 0.0004
4.6334 0.0154 0.0580 0.0004
4.7406 0.0164 0.0566 0.0004
4.9101 0.0166 0.0676 0.0004
5.0624 0.0171 0.0616 0.0004
5.2709 0.0188 0.0762 0.0004
5.4508 0.0180 0.0739 0.0004
5.6180 0.0189 0.0724 0.0004
5.8853 0.0192 0.0825 0.0004
6.0036 0.0199 0.0798 0.0004
6.1707 0.0219 0.0968 0.0005
6.3741 0.0206 0.0880 0.0005
6.5337 0.0215 0.0915 0.0004
6.8124 0.0211 0.1028 0.0005
6.9312 0.0222 0.1058 0.0004
7.1312 0.0227 0.1030 0.0005
8.2538 0.0266 0.1238 0.0005
8.5937 0.0243 0.1033 0.0006
7.7826 0.0248 0.1040 0.0004
8.1156 0.0272 0.1137 0.0005
8.3723 0.0261 0.1245 0.0006
8.5101 0.0262 0.1351 0.0006
8.6796 0.0272 0.1374 0.0006
8.9729 0.0279 0.1339 0.0006
9.2011 0.0285 0.1350 0.0006
9.6675 0.0288 0.1466 0.0005
9.8925 0.0304 0.1452 0.0006
10.0381 0.0328 0.1553 0.0008
10.4903 0.0315 0.1671 0.0007
10.5815 0.0308 0.1627 0.0006
10.8701 0.0327 0.1761 0.0006
11.1378 0.0331 0.1651 0.0007
11.2975 0.0342 0.1768 0.0006
11.4691 0.0352 0.1916 0.0006
11.7784 0.0370 0.1795 0.0007
12.1960 0.0357 0.1776 0.0006
12.4342 0.0374 0.1897 0.0007
12.6972 0.0415 0.2034 0.0006
13.0002 0.0380 0.2269 0.0007
13.2209 0.0394 0.2218 0.0006
13.5231 0.0410 0.2234 0.0008
13.7816 0.0403 0.2123 0.0007
14.1996 0.0415 0.2354 0.0009
14.6795 0.0426 0.2491 0.0007
14.8138 0.0436 0.2456 0.0009
14.9901 0.0425 0.2394 0.0007
15.5859 0.0455 0.2608 0.0008
15.9803 0.0457 0.2673 0.0008
16.0887 0.0475 0.2418 0.0008
16.3703 0.0487 0.2887 0.0008
16.9425 0.0492 0.3165 0.0008
18.7806 0.0584 0.3333 0.0010
21.7533 0.0506 0.3116 0.0008
20.3409 0.0545 0.2927 0.0008
18.5046 0.0538 0.3411 0.0008
18.6049 0.0529 0.3154 0.0011
19.3019 0.0533 0.3359 0.0010
19.6578 0.0544 0.3567 0.0010
19.9678 0.0555 0.3432 0.0009
20.2023 0.0569 0.3234 0.0012
20.8636 0.0581 0.3588 0.0010
20.8515 0.0568 0.3348 0.0009
21.5589 0.0593 0.4119 0.0010
21.6361 0.0614 0.3526 0.0012
21.9093 0.0618 0.3932 0.0011
22.3367 0.0622 0.3873 0.0010
22.5436 0.0633 0.4033 0.0010
23.1500 0.0642 0.4152 0.0011
23.8644 0.0657 0.4237 0.0010
24.4362 0.0986 0.4828 0.0012
24.5771 0.0704 0.4227 0.0012
24.6004 0.0675 0.4672 0.0010
25.1526 0.0709 0.4508 0.0012
25.4833 0.0720 0.4298 0.0012
25.8981 0.0719 0.4657 0.0013
26.3997 0.0720 0.4826 0.0013
26.7230 0.0740 0.5216 0.0013
27.2369 0.0739 0.4747 0.0012
27.6131 0.0763 0.5270 0.0012
29.5497 0.0804 0.5495 0.0014
29.7541 0.0804 0.5224 0.0013
29.4014 0.0794 0.5366 0.0014
30.3006 0.0811 0.5419 0.0013
30.7948 0.0825 0.5798 0.0018
31.0410 0.0842 0.5704 0.0012
31.4454 0.0921 0.5945 0.0013
32.7923 0.0839 0.5688 0.0015
33.2333 0.0862 0.5950 0.0015
34.1797 0.0872 0.5905 0.0021
35.1448 0.0925 0.5921 0.0017
35.4237 0.0951 0.6729 0.0016
36.1466 0.0934 0.6738 0.0018
36.6392 0.0945 0.6435 0.0016
37.1361 0.0981 0.6345 0.0014
37.5505 0.0964 0.6789 0.0015
37.9392 0.0975 0.7185 0.0016
38.6308 0.0996 1.5555 0.0020
39.1776 0.0997 0.7734 0.0018
39.7029 0.1030 0.6917 0.0016
40.2277 0.1021 0.6831 0.0015
40.5795 0.1064 0.7645 0.0018
41.5639 0.1138 0.8422 0.0023
41.3331 0.1155 0.7962 0.0019
42.5029 0.1116 0.8032 0.0016
42.6863 0.1089 0.7750 0.0020
43.2784 0.1730 2.2928 0.0019
44.0860 0.1119 0.8629 0.0017
44.9578 0.1144 0.8481 0.0019
45.4306 0.1186 1.0030 0.0020
45.9325 0.1208 0.8851 0.0017
46.9734 0.1220 0.8957 0.0021
47.8684 0.1191 0.9411 0.0022
47.7906 0.1251 0.9779 0.0017
48.5830 0.1206 0.9621 0.0022
49.0313 0.1229 0.9828 0.0022
49.6555 0.1255 0.9881 0.0023
50.4140 0.1258 0.9727 0.0023
51.0908 0.1365 0.9776 0.0023
51.9044 0.1459 1.0970 0.0023
52.7301 0.1314 1.0280 0.0022
53.6985 0.1329 1.3397 0.0017
53.6170 0.1329 1.0780 0.0020
54.6879 0.1364 1.1436 0.0024
55.1210 0.1402 1.1096 0.0020
57.6322 0.1428 1.1453 0.0020
57.0160 0.1417 1.2097 0.0021
我已经准备好运行缺失位的脚本,但我认为可能没有必要。观察以sparse
格式提供矩阵的方式如何增加jac_iter
所需时间的50倍,前者分别为前两列,sparse
和full
。第三列是算法1用完整矩阵计算 P 的时间,最后一列是算法1的迭代。如您所见,如果我们计算结构,算法1需要更长的时间 P ,否则相反,并且在任何情况下sparse
矩阵需要更长时间。显然,从sparse
矩阵中检索条目也比从full
矩阵中检索相同条目要长得多。在F=sprand(4,7,20)
之后,我跑了:
tic
F(1,2);
tt(1)=toc;
toc
tic
F1(1,2);
tt(2)=toc;
toc
两次,得到了:
1.0e-03 *
0.612686000000000 0.001495000000000
1.0e-04 *
0.547670000000000 0.020670000000000
在左侧,检索F(1,2)
,sparse
格式的时间;在右边,相同的条目,但来自F1=full(F)
。无论如何,稀疏矩阵的数量超过10倍。这是为什么?如何优化稀疏矩阵的Jacobi算法?
答案 0 :(得分:0)
我不是matlab的专家,但我认为你的问题是普遍的问题。在第一个算法中,您进行的计算少于第二个算法。更准确地说,在第一种情况下,一些计算只执行一次,而在第二种情况下,它们会在while循环的每次迭代中重复。
如果我正确理解您的代码,请使用第一个算法中的以下片段:
diagon=diag(A,0);
D=diag(diagon);
LU=A-D;
tic
Dinv=inv(D);
invt=toc;
P=Dinv*LU;
c=Dinv*b;
是第二种算法中 jac_iter 函数的等价物。不同之处在于,当 jac_iter 函数在 while 循环中多次执行时,此片段仅在 循环之前执行一次,并且它是一个优化的地方。
<强>更新强>
在我看来,如果您的数据不是非常稀疏的,即当它们包含很多非零值时,您不应该使用稀疏矩阵。在上一个示例中,您使用了以下代码 F = sprand(4,7,20)。 sprand 函数的最后一个参数取0到1的值。通过指定20作为第三个参数,您创建了一个不包含零的稀疏矩阵。
以下代码显示了稀疏矩阵和完整矩阵的行为,具体取决于矩阵中的零个数。我测量了乘法和读取矩阵中所有单元的时间:
density = [0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 0.75, 0.95];
N = 1000
for x=1:length(density)
A = sprand(N,N,density(x));
elapsed(x,1) = density(x);
tic;
Z = A*A;
elapsed(x,2)=toc;
tic;
sum = 0;
for i=1:N
for j=1:N
sum = sum + A(i,j);
end
end
elapsed(x,3)=toc;
B = full(A);
tic;
Y = B*B;
elapsed(x,4)=toc;
tic;
sum2 = 0;
for i=1:N
for j=1:N
sum2 = sum2 + B(i,j);
end
end
elapsed(x,5)=toc;
end
N = 100的结果是:
Density Sparse Sparse Full Full
multip. retrieval multip. retrieval
0.0100 0.0001 0.0795 0.0030 0.0002
0.0200 0.0001 0.0996 0.0153 0.0002
0.0500 0.0002 0.0959 0.0031 0.0002
0.1000 0.0006 0.1651 0.0007 0.0002
0.2500 0.0013 0.1110 0.0080 0.0002
0.5000 0.0019 0.0898 0.0006 0.0002
0.7500 0.0012 0.0861 0.0052 0.0002
0.9500 0.0025 0.0823 0.0161 0.0002
N = 1000的结果是:
Density Sparse Sparse Full Full
multip. retrieval multip. retrieval
0.0100 0.0088 7.5884 0.1216 0.1047
0.0200 0.0464 7.3136 0.1149 0.0521
0.0500 0.0827 7.0464 0.1733 0.0811
0.1000 0.1265 7.3251 0.0739 0.0563
0.2500 0.2088 7.5518 0.1392 0.0702
0.5000 0.5299 8.1214 0.0895 0.0579
0.7500 0.9524 9.0760 0.0836 0.1023
0.9500 1.3971 9.1553 0.1006 0.1208
结论很简单。如果矩阵中有很多零,则稀疏格式很好。此外,如果要逐个访问单元格,则不应使用稀疏矩阵。当然,对于较小的矩阵,差异并不那么重要。