-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib_gauss.cpp
148 lines (117 loc) · 3.68 KB
/
lib_gauss.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* lib_gauss.cpp
*
* Created on: May 7, 2022
* Author: d-w-h
*/
#include <math.h>
#include <stdio.h>
#include <time.h>
#include "lib_mat.hpp"
#include "lib_mem.hpp"
#include "lib_sort.hpp"
#include "user_types.hpp"
void get_order(double ** mat, int n, double * order_arr) {
for(int row = 0; row < n; ++row) {
int order = 0;
while(fabs(mat[row][order]) <= SMALL_NUM && order < n) {
mat[row][order] = 0.0;
order++;
}
order_arr[row] = order;
}
}
int count_leading_zeros(double ** mat, int n, int row) {
int count = 0;
while(fabs(mat[row][count]) <= SMALL_NUM && count < n) {
count++;
}
return count;
}
void init_mat_inv(double ** mat_inv, int n) {
for(int row = 0; row < n; ++row) {
for(int c = 0; c < n; ++c) {
if(c == row) {
mat_inv[row][c] = 1.0;
}
else {
mat_inv[row][c] = 0.0;
}
}
}
}
void check_leading_zeros(double ** mat, int n, bool & is_singular) {
// Check if matrix is singular
for(int row = 0; row < n; ++row) {
int num_lead_zeros = count_leading_zeros(mat, n, row);
if(num_lead_zeros >= row + 1 && !is_singular) {
printf("Matrix is singular\n");
is_singular = true;
}
}
}
void sort_mat(double * order_arr, int n, double ** mat) {
double ** mat_ordered = mat2D(n);
mergesort_mat(mat, n, order_arr, mat_ordered);
for(int row = 0; row < n; ++row) {
for(int c = 0; c < n; ++c) {
mat[row][c] = mat_ordered[row][c];
// Cut numerically low values
if(fabs(mat[row][c]) <= SMALL_NUM) {
mat[row][c] = 0.0;
}
}
}
free_mat2D(mat_ordered, n);
}
void gauss_jordan(double ** mat, int n, double ** mat_inv) {
double * order_arr = new double[n];
// Initialize matrix inverse
init_mat_inv(mat_inv, n);
// Initialize singularity flag
bool is_singular = false;
// Convert to row echelon form
for(int c = 0; c < n; ++c) {
// Sort if under threshold
if(fabs(mat[c][c]) <= SMALL_NUM) {
get_order(mat, n, order_arr);
sort_mat(order_arr, n, mat);
sort_mat(order_arr, n, mat_inv);
check_leading_zeros(mat, n, is_singular);
}
// Normalize matrix row
for(int col = c + 1; col < n; ++col) {
mat[c][col] = fabs(mat[c][c]) <= SMALL_NUM ? 0.0 : mat[c][col] / mat[c][c];
}
// Update row matrix inverse
for(int col = 0; col < n; ++col) {
mat_inv[c][col] = fabs(mat[c][c]) <= SMALL_NUM ? 0.0 : mat_inv[c][col] / mat[c][c];
}
mat[c][c] = 1.0;
// Delete elements in rows below
for(int row = c + 1; row < n; ++row) {
if(mat[row][c] != 0) {
for(int col = c + 1; col < n; ++col) {
mat[row][col] = -1.0 * mat[row][c] * mat[c][col] + mat[row][col];
}
for(int col = 0; col < n; ++col) {
mat_inv[row][col] = -1.0 * mat[row][c] * mat_inv[c][col] + mat_inv[row][col];
}
mat[row][c] = 0;
}
}
}
// Backtrack to convert to reduced row echelon form
for(int c = n - 1; c > 0; --c) {
for(int row = c - 1; row > -1; --row) {
if(mat[row][c] != 0) {
for(int col = 0; col < n; ++col) {
mat_inv[row][col] = -1.0 * mat[row][c] * mat_inv[c][col] + mat_inv[row][col];
}
mat[row][c] = 0;
}
}
}
// Free allocated space
delete [] order_arr;
}