Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2008.08.10;
Скачать: [xml.tar.bz2];

Вниз

Быстрое инвертирование матрицы 4х4   Найти похожие ветки 

 
@!!ex ©   (2008-06-27 10:33) [0]

Как?
Посомтрел тут свой код...
Инвертирование матрицы методом Гаусса... Больше 150 строк кода... Вообще не радует....
Возможно есть какое то частное решение, подходящее только для матрицы 4х4, о котором я не знаю?
Как например расчет определителя для матрицы 3х3 методом треугольника.


 
han_malign ©   (2008-06-27 10:47) [1]

http://algolist.manual.ru/maths/linalg/index.php


 
Jeer ©   (2008-06-27 10:53) [2]

Мы тут как-то проезжали эту тему по поводу быстродействия.
Вот один из моих вариантов на 2800 ticks:

{$APPTYPE CONSOLE}
program inv;

uses Math, TimeUnit;

type
TMat4 = array[0..3, 0..3] of double;
TV4   = array[0..15] of double;
var
AA, BB, CC: TMat4;
i, j, k: Integer;
T1,T2: int64;

procedure Inv4(const S; var T);
var det: double;
   A12,A13,A14: double;
   A22,A23,A24: double;
   A32,A33,A34: double;
   A41,A42,A43,A44: double;
   B1,B2,B3,B4,B5,B6,B7,B8: double;
begin

A12 := TV4(S)[1];
A13 := TV4(S)[2];
A14 := TV4(S)[3];
//
A22 := TV4(S)[5];
A23 := TV4(S)[6];
A24 := TV4(S)[7];
//
A32 := TV4(S)[9];
A33 := TV4(S)[10];
A34 := TV4(S)[11];
//
A41 := TV4(S)[12];
A42 := TV4(S)[13];
A43 := TV4(S)[14];
A44 := TV4(S)[15];

B1 := A22*A33*A44 + A23*A34*A42 + A24*A32*A43;
B2 := TV4(S)[4]*A34*A43 + A23*TV4(S)[8]*A44 + A24*A33*A41;
B3 := TV4(S)[4]*A32*A44 + A22*A34*A41 + A24*TV4(S)[8]*A42;
B4 := TV4(S)[4]*A33*A42 + A22*TV4(S)[8]*A43 + A23*A32*A41;

B5 := A22*A34*A43 + A23*A32*A44 + A24*A33*A42;
B6 := TV4(S)[4]*A33*A44 + A23*A34*A41 + A24*TV4(S)[8]*A43;
B7 := TV4(S)[4]*A34*A42 + A22*TV4(S)[8]*A44 + A24*A32*A41;
B8 := TV4(S)[4]*A32*A43 + A22*A33*A41 + A23*TV4(S)[8]*A42;

det := 1.0 / (TV4(S)[0]*(B1-B5) + A12*(B2-B6) + A13*(B3-B7) + A14*(B4-B8));

TV4(T)[0]  := det*(B1 - B5);
TV4(T)[1]  := det*(A12*(A34*A43 - A33*A44) + A13*(A32*A44 - A34*A42) + A14*(A33*A42 - A32*A43));
TV4(T)[2]  := det*(A12*A23*A44 + A13*A24*A42 + A14*A22*A43 - A12*A24*A43 - A13*A22*A44 - A14*A23*A42);
TV4(T)[3]  := det*(A12*A24*A33 + A13*A22*A34 + A14*A23*A32 - A12*A23*A34 - A13*A24*A32 - A14*A22*A33);

TV4(T)[4]  := det*(B2 - B6);
TV4(T)[5]  := det*(TV4(S)[0]*(A33*A44 - A34*A43) + A13*(A34*A41 - TV4(S)[8]*A44) + A14*(TV4(S)[8]*A43 - A33*A41));
TV4(T)[6]  := det*(TV4(S)[0]*(A24*A43 - A23*A44) + A13*(TV4(S)[4]*A44 - A24*A41) + A14*(A23*A41 - TV4(S)[4]*A43));
TV4(T)[7]  := det*(TV4(S)[0]*(A23*A34 - A24*A33) + A13*(A24*TV4(S)[8] - TV4(S)[4]*A34) + A14*(TV4(S)[4]*A33 - A23*TV4(S)[8]));

TV4(T)[8]  := det*(B3 - B7);
TV4(T)[9]  := det*(TV4(S)[0]*(A34*A42 - A32*A44) + A12*(TV4(S)[8]*A44 - A34*A41) + A14*(A32*A41 - TV4(S)[8]*A42));
TV4(T)[10] := det*(TV4(S)[0]*(A22*A44 - A24*A42) + A12*(A24*A41 - TV4(S)[4]*A44) + A14*(TV4(S)[4]*A42 - A22*A41));
TV4(T)[11] := det*(TV4(S)[0]*(A24*A32 - A22*A34) + A12*(TV4(S)[4]*A34 - A24*TV4(S)[8]) + A14*(A22*TV4(S)[8] - TV4(S)[4]*A32));

TV4(T)[12] := det*(B4 - B8);
TV4(T)[13] := det*(TV4(S)[0]*(A32*A43 - A33*A42) + A12*(A33*A41 - TV4(S)[8]*A43) + A13*(TV4(S)[8]*A42 - A32*A41));
TV4(T)[14] := det*(TV4(S)[0]*(A23*A42 - A22*A43) + A12*(TV4(S)[4]*A43 - A23*A41) + A13*(A22*A41 - TV4(S)[4]*A42));
TV4(T)[15] := det*(TV4(S)[0]*(A22*A33 - A23*A32) + A12*(A23*TV4(S)[8] - TV4(S)[4]*A33) + A13*(TV4(S)[4]*A32 - A22*TV4(S)[8]));
 
end;

begin

for i := 0 to 3 do
 for j := 0 to 3 do
  AA[i,j] := 10.0 * random - 5.0;

T1 := GetCPUTicksP_;
Inv4(AA, BB);
T2 := GetCPUTicksP_;

Writeln((T2-T1)," ticks");
WriteLn;

for i := 0 to 3 do begin
  for j := 0 to 3 do begin
    CC[i,j] := 0.0;
    for k := 0 to 3 do
      CC[i,j] := CC[i,j] + AA[i,k] * BB[k,j];
    Write(CC[i,j]:12:6);
  end;
  WriteLn
end;
// Должна вывестись единичная матрица
readln;
end.


 
Jeer ©   (2008-06-27 11:03) [3]

А это вариант с вычислением подматриц 3*3, но хуже по быстродействию.

{$APPTYPE CONSOLE}
program inv;

uses Math;

type
TMat4 = array[0..3, 0..3] of Double;
TV3 = array[0..8] of Double;
TV4 = array[0..15] of Double;

function GetCPUTicksP_:int64;
// 88 ticks
asm
dw 310Fh   // rdtsc
end;

procedure m4_submat(const  mr: TV4; var mb: TV3; i, j: integer );
var
di, dj, si, sj: integer;
begin
si := 0; sj := 0;
// loop through 3x3 submatrix
for di := 0 to  2 do
  for dj := 0 to 2 do begin
// map 3x3 element (destination) to 4x4 element (source)
    if di >= i then si := di + 1
    else si := di;
    if dj >= j then sj := dj + 1
    else sj := dj;
// copy element
    mb[di shl 1 + di + dj] := mr[si shl 2 + sj];
 end;
end;

function m3_det( const mat: TV3 ): double;
begin
  Result := mat[0] * mat[4] * mat[8] - mat[0] * mat[7] * mat[5]
          - mat[1] * mat[3] * mat[8] + mat[1] * mat[6] * mat[5]
          + mat[2] * mat[3] * mat[7] - mat[2] * mat[6] * mat[4];
end;

function m4_det( const mr: TV4 ): double;
var
 det: double;
 i,n: integer;
 msub3: TV3;
 x: double;
begin
 x := 0.0;
 i := 1;
 for  n := 0 to 3 do begin
   i := -i;
   m4_submat( mr, msub3, 0, n );
   det := m3_det( msub3 );
   x := x  + mr[n] * det * i;
 end;
 Result := x;
end;

procedure m4_identity(var mr: TV4);
var i: integer;
begin
 for i:=0 to 3 do
   mr[i*5] := 1.0;
end;

function m4_inverse( var ma, mr ): integer;
var
 mdet: double;
 mtemp: TV3;
 i, j, sgn: integer;
begin

 mdet := 1.0 / m4_det( TV4(ma) );
 if ( abs( mdet ) < 0.0005 ) then begin
   m4_identity( TV4(mr) );
   Result := 0;
   Exit;
 end;
 for i := 0 to 3 do
   for j := 0 to 3 do begin
     sgn := 1 - ( (i + j) mod 2 ) * 2;
     m4_submat( TV4(ma), mtemp, i, j );
     if sgn >=0 then
       TV4(mr)[i + j * 4] := mdet * m3_det( mtemp )
     else
       TV4(mr)[i + j * 4] := - mdet * m3_det( mtemp )

   end;
   Result := 1;
end;

var
AA, BB, CC: TMat4;
i, j, k: integer;
T1,T2: int64;
begin

for i := 0 to 3 do
 for j:= 0 to 3 do begin
  AA[i,j] := 10.0 * random - 5.0;
 end;

T1 := GetCPUTicksP_;
m4_inverse(AA, BB);
T2 := GetCPUTicksP_;

Writeln((T2-T1)," ticks");
WriteLn;

for i := 0 to 3 do begin
  for j := 0 to 3 do begin
    CC[i,j] := 0.0;
    for k := 0 to 3 do
      CC[i,j] := CC[i,j] + AA[i,k] * BB[k,j];
    Write(CC[i,j]:12:6);
  end;
  WriteLn;
end;
// Должна вывестись единичная матрица
readln;
end.

P.S.

У Intel  в апноте AP-928 за 1999 г. есть примеры использования SIMD для инверсии матрицы 4*4.
С использованием правила Крамера там вообще вышло 210 cycles :)


 
Sapersky   (2008-06-27 12:12) [4]

Мы тут как-то проезжали эту тему по поводу быстродействия.

Причём @!!ex же и спрашивал, примерно год назад.
Вот эта ветка (не полностью, в архиве лень ковыряться):
http://narod.ru/disk/1147837000/InverseMatrix.zip


 
@!!ex ©   (2008-06-27 12:47) [5]

> [4] Sapersky   (27.06.08 12:12)

Какая память однако. :) Я уже и забыл что спрашивал это.


 
@!!ex ©   (2008-06-27 12:49) [6]

Вот есть такой вариант:
http://www.everfall.com/paste/id.php?z0neuzcvr9fy

Насколько это в тему?

P.S.
Да, матрица не общая, матрица хранит только вращение.


 
@!!ex ©   (2008-06-27 13:02) [7]

Это в тему. Работает.


 
Zeqfreed ©   (2008-06-27 13:11) [8]

> Да, матрица не общая, матрица хранит только вращение.

На википедии написано:
In matrix theory, a rotation matrix is a real square matrix whose transpose is its inverse and whose determinant is +1.

http://en.wikipedia.org/wiki/Rotation_matrix


 
Sapersky   (2008-06-27 14:27) [9]

http://www.everfall.com/paste/id.php?z0neuzcvr9fy

Похоже на вариант, который я давал ещё в той ветке, но математически сокращённый (корректность преобразований не проверял). Хотя в моём несколько оптимальнее считалась последняя строка матрицы, с учётом m->_11*l1 = res->_11 и т.д.


 
@!!ex ©   (2008-06-27 14:43) [10]

> [9] Sapersky   (27.06.08 14:27)

Раз уж ты все равно здесь, может поможешь разобраться, почему SV не корректно строится?
http://img80.imageshack.us/img80/6520/swbugvz6.jpg


 
Sapersky   (2008-06-27 17:13) [11]

Сходу не скажу - 3D-графикой давно не занимался, да и год назад только эпизодически поковырялся с SV, так что о типовых глюках имею слабое представление.
Не знаю, имеет ли смысл отсылать сюда:
http://delphimaster.net/view/9-1181032876/
хотя судя по начальному вопросу ветки, смысл вполне может быть :)
Во всяком случае, там пример гарантированно работающего кода, правда, он относится к z-pass, для z-fail нужны ещё передняя/задняя "затычки".


 
Sapersky   (2008-06-27 18:07) [12]

Могу предположить, что моделька кривовата, некоторые треугольники - двухсторонние, и рёбра их "задних" сторон воспринимаются как часть силуэта (алгоритм выделения "силуэтных" ребёр определяет их по одинарному вхождению в список, и для одиночных "задних" cторон это условие соблюдается).


 
@!!ex ©   (2008-06-27 18:20) [13]

У меня код из http://delphimaster.net/view/9-1181032876/ не пахал нормально.
ПРишлось дублировать грани.
А проблема на скриншоте тупо в том, что я нормаль не правильно считал... :)
Когда писал перемножение векторов, в одном месте вместо x - y написал... и все поломалось.



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2008.08.10;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.007 c
15-1214226247
dert333
2008-06-23 17:04
2008.08.10
Ошибка с установками


2-1215491519
hater
2008-07-08 08:31
2008.08.10
Параметры


2-1215687715
pathfinder
2008-07-10 15:01
2008.08.10
Поля классов.


2-1215156404
laao
2008-07-04 11:26
2008.08.10
объясните поведение Delphi при выполнении следующего кода


15-1214391891
Big Joe
2008-06-25 15:04
2008.08.10
Домены меняют алфавит





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский