İçin hızlı açık çözüm


9

3x3 doğrusal gerçek sorun hızlı bir çözüm (en uygun demeye cesaret?) Arıyorum, Ax=b, AR3×3,bR,3.

Matris bir geneldir ancak 1'e yakın bir koşul numarasıyla kimlik matrisine yakındır. b aslında yaklaşık 5 basamaklı sensör ölçümleri, sayısal sorunlar nedeniyle birkaç basamak kaybetmeyi umursamıyorum.

Tabii ki, herhangi bir sayıda yönteme dayanan açık bir çözüm bulmak zor değildir, ancak FLOPS sayımı açısından optimal olduğu gösterilen bir şey varsa, bu ideal olacaktır (sonuçta, tüm sorun büyük olasılıkla FP kayıtlarına sığacaktır!).

(Evet, bu rutin sık sık denir . Zaten düşük asılı meyveden kurtuldum ve bu bir sonraki profilleme listemde ...)


Her biri birsadece bir kez kullanılır mı, yoksa aynı matrise sahip birden fazla doğrusal sistem var mı? Bu maliyetleri değiştirir.
Federico Poloni

Bu durumda, A yalnızca bir kez kullanılır.
Damien

Yanıtlar:


14

Açık bir formülü yenemezsin. Çözüm için formülleri yazabilirsinizx=bir-1bbir parça kağıt üzerinde. Derleyicinin işleri sizin için optimize etmesine izin verin. Başka herhangi bir yöntem neredeyse kaçınılmaz olarak kodunuzu herhangi bir düz satır kodundan daha yavaş yapacak ififadelere veya fordöngülere (örneğin yinelemeli yöntemler için) sahip olacaktır.


9

Matris kimliğe çok yakın olduğu için, aşağıdaki Neumann serisi çok hızlı bir şekilde birleşecektir:

bir-1=Σk=0(ben-bir)k

Gereken doğruluğa bağlı olarak, 2 terimden sonra kesilecek kadar iyi olabilir:

bir-1ben+(ben-bir)=2ben-bir.

Bu, daha az doğrulukla, doğrudan bir formülden (Wolfgang Bangerth'ın cevabında önerildiği gibi) biraz daha hızlı olabilir.


3 terimle daha fazla doğruluk elde edebilirsiniz:

bir-1ben+(ben-bir)+(ben-bir)2=3ben-3bir+bir2

ancak giriş giriş formülünü yazarsanız, (3ben-3bir+bir2)b, doğrudan 3x3 matris ters formülü olarak karşılaştırılabilir bir kayan nokta işlemi miktarına bakıyorsunuz (yine de bir bölüm yapmak zorunda değilsiniz, bu da biraz yardımcı olur).


Bölümler hala diğer floplardan daha mı pahalı? Geçmişin bir kalıntısı olduğunu düşündüm.
Federico Poloni

Bölümler bazı mimarileri iyi bir şekilde sıralamıyor (ARM çağdaş örnek)
Damien

@FedericoPoloni Cuda ile burada talimat çıktısını görebilirsiniz , çarpma / toplama işlemleri için bölme işleminden altı kat daha fazladır.
Kirill

@Damien ve Kirill, işaretçiler için teşekkürler.
Federico Poloni

5

FLOPS yukarıdaki önerilere göre sayılır:

  • LU, pivot yok:

    • Mul = 11, Div / Recip = 6, Add / Sub = 11, Toplam = 28; veya
    • Mul = 16, Div / Recip = 3, Add / Sub = 11, Toplam = 30
  • Geri ikame ile Gauss eliminasyonu, pivot yok:

    • Mul = 11, Div / Recip = 6, Add / Sub = 11, Toplam = 28; veya
    • Mul = 16, Div / Recip = 3, Add / Sub = 11, Toplam = 30
  • Kofaktör genişlemesi yoluyla Cramer kuralı

    • Mul = 24, Div = 3, Toplama / Alt = 15, Toplam = 42; veya
    • Mul = 27, Div = 1, Ekle / Alt = 15, Toplam = 43
  • Açık Inverse sonra çarpın:

    • Mul = 30, Div = 3, Add / Sub = 17, Toplam = 50; veya
    • Mul = 33, Div = 1, Ekle / Alt = 17, Toplam = 51

MATLAB kavram kanıtı:

Cofactor Genişletme Yoluyla Cramer Kuralı :

function k = CramersRule(A, m)
%
% FLOPS:
%
% Multiplications:        24
% Subtractions/Additions: 15
% Divisions:               3
%
% Total:                  42

a = A(1,1);
b = A(1,2);
c = A(1,3);

d = A(2,1);
e = A(2,2);
f = A(2,3);

g = A(3,1);
h = A(3,2);
i = A(3,3);

x = m(1);
y = m(2);
z = m(3);

ei = e*i;
fh = f*h;

di = d*i;
fg = f*g;

dh = d*h;
eg = e*g;

ei_m_fh = ei - fh;
di_m_fg = di - fg;
dh_m_eg = dh - eg;

yi = y*i;
fz = f*z;

yh = y*h;
ez = e*z;

yi_m_fz = yi - fz;
yh_m_ez = yh - ez;

dz = d*z;
yg = y*g;

dz_m_yg = dz - yg;
ez_m_yh = ez - yh;


det_a = a*ei_m_fh - b*di_m_fg + c*dh_m_eg;
det_1 = x*ei_m_fh - b*yi_m_fz + c*yh_m_ez;
det_2 = a*yi_m_fz - x*di_m_fg + c*dz_m_yg;
det_3 = a*ez_m_yh - b*dz_m_yg + x*dh_m_eg;


p = det_1 / det_a;
q = det_2 / det_a;
r = det_3 / det_a;

k = [p;q;r];

LU (pivot yok) ve geri değiştirme:

function [x, y, L, U] = LUSolve(A, b)
% Total FLOPS count:     (w/ Mods)
%
% Multiplications:  11    16
% Divisions/Recip:   6     3
% Add/Subtractions: 11    11
% Total =           28    30
%

A11 = A(1,1);
A12 = A(1,2);
A13 = A(1,3);

A21 = A(2,1);
A22 = A(2,2);
A23 = A(2,3);

A31 = A(3,1);
A32 = A(3,2);
A33 = A(3,3);

b1 = b(1);
b2 = b(2);
b3 = b(3);

L11 = 1;
L22 = 1;
L33 = 1;

U11 = A11;
U12 = A12;
U13 = A13;

L21 = A21 / U11;
L31 = A31 / U11;

U22 = (A22 - L21*U12);
L32 = (A32 - L31*U12) / U22;

U23 = (A23 - L21*U13);

U33 = (A33 - L31*U13 - L32*U23);

y1 = b1;
y2 = b2 - L21*y1;
y3 = b3 - L31*y1 - L32*y2;

x3 = (y3                  ) / U33;
x2 = (y2 -          U23*x3) / U22;
x1 = (y1 - U12*x2 - U13*x3) / U11;

L = [ ...
    L11,   0,   0;
    L21, L22,   0;
    L31, L32, L33];

U = [ ...
    U11, U12, U13;
      0, U22, U23;
      0,   0, U33];

x = [x1;x2;x3];
y = [y1;y2;y3];

Açık Inverse sonra Çarpma:

function x = ExplicitInverseMultiply(A, m)
%
% FLOPS count:                  Alternative
%
% Multiplications:        30            33
% Divisions:               3             1
% Additions/Subtractions: 17            17
% Total:                  50            51


a = A(1,1);
b = A(1,2);
c = A(1,3);

d = A(2,1);
e = A(2,2);
f = A(2,3);

g = A(3,1);
h = A(3,2);
i = A(3,3);

ae = a*e;
af = a*f;
ah = a*h;
ai = a*i;

bd = b*d;
bf = b*f;
bg = b*g;
bi = b*i;

cd = c*d;
ce = c*e;
cg = c*g;
ch = c*h;

dh = d*h;
di = d*i;

eg = e*g;
ei = e*i;

fg = f*g;
fh = f*h;

dh_m_eg = (dh - eg);
ei_m_fh = (ei - fh);
fg_m_di = (fg - di);

A = ei_m_fh;
B = fg_m_di;
C = dh_m_eg;
D = (ch - bi);
E = (ai - cg);
F = (bg - ah);
G = (bf - ce);
H = (cd - af);
I = (ae - bd);

det_A = a*ei_m_fh + b*fg_m_di + c*dh_m_eg;

x1 =  (A*m(1) + D*m(2) + G*m(3)) / det_A;
x2 =  (B*m(1) + E*m(2) + H*m(3)) / det_A;
x3 =  (C*m(1) + F*m(2) + I*m(3)) / det_A;

x = [x1;x2;x3];

Gauss elimine etme:

function x = GaussianEliminationSolve(A, m)
%
% FLOPS Count:      Min   Alternate
%
% Multiplications:  11    16
% Divisions:         6     3
% Add/Subtractions: 11    11
% Total:            28    30
%

a = A(1,1);
b = A(1,2);
c = A(1,3);

d = A(2,1);
e = A(2,2);
f = A(2,3);

g = A(3,1);
h = A(3,2);
i = A(3,3);

b1 = m(1);
b2 = m(2);
b3 = m(3);

% Get to echelon form

op1 = d/a;

e_dash  = e  - op1*b;
f_dash  = f  - op1*c;
b2_dash = b2 - op1*b1;

op2 = g/a;

h_dash  = h  - op2*b;
i_dash  = i  - op2*c;
b3_dash = b3 - op2*b1; 

op3 = h_dash / e_dash;

i_dash2  = i_dash  - op3*f_dash;
b3_dash2 = b3_dash - op3*b2_dash;

% Back substitution

x3 = (b3_dash2                  ) / i_dash2;
x2 = (b2_dash        - f_dash*x3) / e_dash;
x1 = (b1      - b*x2 -      c*x3) / a;

x = [x1 ; x2 ; x3];

Not: Lütfen bu gönderiye kendi yöntemlerinizi ve sayılarınızı eklemekten çekinmeyin.


İki yöntemle çözülmesi gereken süreleri hesapladınız mı?
nicoguaro

Hayır. Yukarıdaki kod hiç hızlı bir şekilde yürütülmez. Amacı açık bir FLOPS sayımı almak ve bir şey kaçırmışsam inceleme için kod sağlamaktı,
Damien

LU'da, 5 bölüm 2 ekstra karşılıklı işlem pahasına 5 MUL'a dönüştürülebilir (yani 1 / U11 ve 1 / U22). Bu, orada kazanılacak bir kazanım olup olmadığı konusuna özgü olacaktır.
Damien

2
Yanlış saymadığımı varsayarsak, yaklaşık bir-1b tarafından 2b-birb12 çarpma, 9 toplama / çıkarma ve bölme gerektirmeyecektir. Yaklaşık Hesabıbir-1b tarafından 3(b-birb)+bir2b21 çarpma ve 18 toplama / çıkarma gerektirecektir. Hesaplanıyorbir-1bBu açık formül aracılığıyla 33 çarpma, 17 toplama / çıkarma ve 1 bölme gibi görünüyor. Dediğim gibi, sayılarım kapalı olabilir, bu yüzden iki kez kontrol etmek isteyebilirsiniz.
Geoff Oxberry

@ GeoffOxberry, içine bakacağım ve rapor edeceğim.
Damien

4

Muhtemelen Cramer Kuralı. Pivotlamadan kaçınabilirseniz, belki LU çarpanlarına ayırma; 3x3'lük bir matristir, bu yüzden döngüleri manuel olarak açmak kolay olurdu. Başka bir şey muhtemelen dallanmayı içerecektir ve bir Krylov altuzay yönteminin buna değer olması için 1 veya 2 yinelemede yeterince yakınsak olacağından şüpheliyim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.