русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Операції з матрицями


Дата додавання: 2014-11-28; переглядів: 1330.


 

Матричні обчислення відіграють значну роль при розв’язанні прикладних задач. Вони покладені в основу математичного апарата квантової й статистичної механіки й фізики, радіоелектроніки, теорії коливань, де фундаментальне значення мають характеристичні рівняння, власні числа й вектори. Алгоритми лінійної алгебри є складовою частиною алгоритмів розв’язування дуже великої кількості лінійних і нелінійних задач моделювання і обробки даних, задач оптимізації, багатьох інших задач у наукових дослідженнях, технічних розробках, розв’язуванні економічних проблем. У даному підрозділі розглядаються декілька алгоритмів лінійної алгебри, які використовуються найбільш часто.

Звертаємо увагу на те, що у загально-математичних формулюваннях нумерація елементів масивів починається з 1, в той час як у програмних реалізаціях, які наводяться, нумерація, згідно з традиціями мови С, починається з 0.

 

Задача обчислення сідлової точки матриці

Задана прямокутна матриця А розміром N´M. Потрібно обчислити її мінімаксну сідлову точку за формулою :

, (1)

або максимінну сідлову точку:

. (2)

Алгоритм

Алгоритм випливає прямо з формул (1) і (2).

 

Нижче наведені дві функції, які повертають значення сідлових точок матриці з елементами типу double.

 

// Приклад 1

double MinMax (double** A, int N, int M )

{ int i,j; double minmax;

double* D = new double[N];// створення допоміжного масиву

for (i=0; i<N; i++)

{ D[i] = A[i][0];

for (j=1; j<M; j++) if (A[i][j]>D[i]) D[i] = A[i][j];

}

// знайти найменший серед найбільших

minmax = D[0];

for (i=1; i<N; i++) if (D[i] < minmax) minmax = D[i];

delete[] D;

return minmax;

}

 

// Приклад 2

double MaxMin (double** A, int N, int M )

{ int i,j; double maxmin;

double* D = new double[N];

for (i=0; i<N; i++)

{ D[i] = A[i][0];

for (j=1; j<M; j++) if (A[i][j]<D[i]) D[i] = A[i][j];

}

maxmin = D[0];

for (i=1; i<N; i++) if (D[i] > maxmin) maxmin = D[i];

delete [] D;

return maxmin;

}

 

Задача обчислення визначника матриці

Задана квадратна числова матриця:

. (3)

Обчислити її визначник det(A).

 

Алгоритм

До еквівалентних перетворень відносять такі перетворення, які не змінюють визначник матриці. Використовуючи певну послідовність еквівалентних перетворень, вихідну матрицю можна звести до трикутного вигляду:

. (4)

Визначник такої матриці легко обчислюється шляхом отримання добутку діагональних елементів:

det (A) = det (A') = . (5)

Якщо при виконанні перетворень матриці виконувались операції перестановки рядків, то формула для обчислення визначника дещо змінюється:

, (6)

де p - кількість операцій парної перестановки рядків.

Для того, щоб перетворити елемент матриці akj, що лежить нижче головної діагоналі, у нуль, треба отримати нові елементи k-того рядка за такою формулою:

, . (7)

З останньої формули видно, що діагональний елемент aii повинен бути відмінним від нуля. Щоб цього уникнути, і, одночасно, збільшити точність і надійність обчислення визначника, застосовується прийом, названий «вибором головного елемента». Цей прийом полягає в наступному. Припустимо в i-м стовпці необхідно перетворити в нуль елементи, що лежать нижче головної діагоналі. Серед елементів цього стовпця, починаючи з aii і до останнього елемента ani, знаходимо максимальний по модулю елемент. Потім міняємо місцями i-тий рядок і рядок, що містить максимальний по модулю елемент, місцями. Таким чином, на місці діагонального елемента завжди буде максимальний (по абсолютній величині) з можливих елементів. Якщо знайдений максимальний елемент дорівнює нулю, то обчислення можна завершити: визначник у цьому випадку буде дорівнювати нулю.

Нижче наводиться приклад функції DetMatr(A,N), яка обчислює визначник матриці A розміром N´N. Обчислення виконуються відповідно до дійсного типу double.

 

// Приклад 3

double DetMatr(double** A, unsigned N )

{ int i, j, k=0;

double D, R;

double** C= new double*[N];// створення робочої

for (i=0; i<N; i++) C[i]=new double[N]; // матриці С

for (i=0; i<N; i++)

for (j=0; j<N; j++) C[i][j] = A[i][j];

// копіювання матриці

for (i=0; i<N-1; i++) // основний цикл

{// вибираємо головний елемент

D=fabs(C[i][i]);

k=i;

for (j=i+1; j<N; j++)

if (fabs(C[j][i])>D) { k = j; D = fabs(C[j][i]); }

// міняємо, якщо треба, рядки місцями

if (k!=i) swp(C[k],C[i]);

// перетворення в нуль елементів стовпцяR = 1./C[i][i];

for (k=i+1; k<N; k++)

{ D = C[k][i]*R;

for (j=i; j<N; j++) C[k][j] = C[k][j]- D*C[i][j];

}

}

// отримаємо визначник як добуток елементів
// головної діагоналі

D= 1.0;

for (i=0; i<N; i++) D *= C[i][i];

for (i=0; i<N; i++) delete[] C[i];// звільнення пам’яті

delete[] C;

return D;

}

 

 

Задача обчислення оберненої матриці

Надана квадратна числова матриця А з розмірами n´n. Отримати матрицю A-1, яка відповідає такій умові:

A× A-1 = A-1× A = I , (8)

де I - одинична діагональна матриця.

 

Алгоритм

Створимо робочу прямокутну матрицю С розміром n´2n, приписавши праворуч до вихідної матриці A одиничну діагональну матрицю E такого ж розміру:

. (9)

Виконаємо над цією розширеною матрицею перетворення, мета яких - перетворити у нулі всі елементи, що лежать нижче головної діагоналі лівої частини матриці. Операції перетворення рядків виконуємо над рядками розширеної матриці в цілому, включаючи одиничну підматрицю. Перетворення проводяться в три етапи:

1. Перетворюємо в нулі всі елементи підматриці А, які лежать нижче головної діагоналі.

2. Перетворюємо в нулі всі елементи підматриці А, що лежать вище головної діагоналі.

3. Перетворюємо всі діагональні елементи підматриці А в одиниці, шляхом ділення кожного рядка розширеної матриці на відповідний діагональний елемент.

Після виконання цих кроків, підматриця А стане одиничною, а підматриця Е перетвориться в шукану обернену матрицю А-1. У наведеному алгоритмі можна також застосувати вибір головного елемента, відповідна операція виконується на етапі 1.

Нижче наведено функцію ObrMatr, яка реалізує поданий вище алгоритм. Вхідна матриця зберігається в масиві А, зворотна записується в масив В, N - розмір матриці. Двовимірний масив B відповідних розмірів повинен бути створений заздалегідь.

 

// Приклад 4

void ObrMatr (double** A, double** B, unsigned N )

{ int i, j, k=0, N2=N*2;

double D, R;

double** C = new double*[N];// створення робочої матриці С

for (int i=0; i<N; i++) C[i] = new double[N2];

for (i=0; i<N; i++)

{ for (j=0; j<N; j++) { C[i][j]=A[i][j]; C[i][N+j]=0; }

C[i][i+N] = 1;

}

// зведення до нуля елементів підматриці А нижче головної
// діагоналі

for (i=0; i<N-1; i++)

{ D=fabs(C[i][i]);

k=i;

for (j=i+1; j<N; j++)

if (fabs(C[j][i])>D) { k=j; D=fabs(C[j][i]); }

if (k!=i) swp(C[k],C[i]);// вибір головного елемента

R = 1./C[i][i];

for (k=i+1; k<N; k++)

{ D = C[k][i]*R;

for (j=i; j<N2; j++) C[k][j] = C[k][j]- D*C[i][j];

}

}

// зведення до нуля елементів подматриці А вище головної
// діагоналі

for (i=0; i<N; i++)

{ D = C[i][i];

for (j=0; j<N2; j++) C[i][j]=C[i][j]/D;

}

for (i=1; i<N; i++)

for (k=0; k<i; k++)

{ D= C[k][i];

for (j=i; j<N2; j++) C[k][j]=C[k][j]-C[i][j]*D;

}

// вибір елементів оберненої матриці B

for (i=0; i<N; i++) for (j=0; j<N; j++) B[i][j] = C[i][j+N];

for (i=0; i<N; i++) delete[] C[i];// звільнення пам'яті

delete[] C;

}

 

Нижче наведено ще одну функцію для обернення матриці, яка реалізує так званий метод заміщення за схемою Гауса. Параметри функції: A - матриця, що надана, B - обернена матриця, N - розмір матриць А,В. Як і раніше, двовимірний масив B відповідних розмірів повинен бути створений заздалегідь. Метод заміщення є більш економним по відношенню до ресурсів пам’яті, але застосування вибору головного елемента у цьому разі неможливе.

 

// Приклад 5

void Minv(double** A, double** B, unsigned N )

{ int i, j, k;

double R;

for (i=0; i<N; i++) for (j=0; j<N; j++) B[i][j]=A[i][j];

for (i=0; i<N; i++)

{ R = 1./B[i][i];

for (j=0; j<N; j++) B[i][j] = B[i][j]*R;

B[i][i] = R;

for (k=0; k<N; k++)

{ if (k!=i)

{ for (j=0; j<N; j++)

if (j!=i) B[k][j]=B[k][j]-B[i][j]*B[k][i];

B[k][i] = -R*B[k][i];

}

}

}

}

 

Задача розв’язування системи лінійних рівнянь

Надана система лінійних рівнянь:

. (10)

Треба знайти значення x1, x2, ... , xn , які задовольняють системі рівнянь.

 

Алгоритм

Розглянемо один з класичних методів розв’язання систем лінійних рівнянь - метод Гауса з вибором головного елемента в стовпці. Він заснований на приведенні матриці коефіцієнтів до трикутного виду.

У матричній формі система лінійних рівнянь (10) приймає такий вид:

А*Х=В , (11)

де

, , .

У методі Гауса використаються наступні фундаментальні властивості лінійних систем:

- перестановка рядків матриці А і відповідних елементів вектору B (тобто перестановка рівнянь у системі (10)) не змінює розв’язку системи;

- додаток до рядка елементів іншого рядка або лінійної комбінації рядків не змінює розв’язку системи.

При чисельному розв’язуванні над системою виконуються перетворення, метою яких є отримання системи з трикутною матрицею А. Після вказаного приведення виконується другий етап алгоритму - зворотній хід. Обчислення виконується по формулі:

.

Реалізація методу Гауса у вигляді функції Gauss наведена нижче. Параметрами функції є: A - матриця системи, B - вектор правих частин, X - вектор-розв’язок системи, N - кількість рівнянь.

 

// Приклад 6

void Gauss(double** A, double* B, double* X, unsigned N)

{ int i, j, k=0;

double D, R;

// прямий хід

for (i=0; i<N-1; i++)

{// вибір головного елемента

D=fabs(A[i][i]);

k=i;

for (j=i+1; j<N; j++)

if (fabs(A[j][i])>D) { k=j; D=fabs(A[j][i]); }

// якщо потрібно, то поміняти місцями рядки

if (k!=i) { swp(A[k],A[i]); swp(B[k],B[i]);

// перетворення матриці у трикутну

R = 1./A[i][i];

for (k=i+1; k<N; k++)

{ D=A[k][i]*R;

for (j=i; j<N; j++) A[k][j]=A[k][j]-D*A[i][j];

B[k]=B[k]-D*B[i];

}

}

// зворотний хід

X[N-1] = B[N-1]/A[N-1][N-1];

for (i=(N-2); i>=0; i--)

{ D = 0.0;

for (j=i+1; j<N; j++) D += A[i][j]*X[j];

X[i] = (B[i]-D)/A[i][i];

}

}

 

 


<== попередня лекція | наступна лекція ==>
Сортування масивів | Лінійна інтерполяція даних


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн