-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGauss-Seidel_method.c
325 lines (300 loc) · 14.9 KB
/
Gauss-Seidel_method.c
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
// Написать программу, решающую СЛАУ методом Гаусса-Зейделя
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#define MIN 0.0001
#define ITER 7
#define CONST 3
void fillMatrix(FILE* f, double** m, int sz1, int sz2);
// Функция, считывающая значения коэффициентов из файла и заполяющая ими матрицу
void print2(double** m, int sz1); // Функция печати двумерного массива
void print1(double* x, int sz1); // Функция печати одномерного массива
double* create1(int sz); // Функция выделения памяти под массив решения системы
double** create2(int sz1, int sz2); // Функция, создающая двумерный массив
void erase2(double** m, int sz1, int sz2); // Функция, удаляющая из памяти двумерный массив
int check_diagonal(double** m, int* index, int sz2); // Функция, проверяющая, есть ли на диагонали нули
double* get_sum(double** m, int sz1); // Функция, считающая сумму эл-тов каждой строки
int check_convergence(double** m, int* index, double* sum, int sz1); // Функция, проверяющая ДУС
double* iteration(double** m, double* x, double* pred, int sz1); // Итерация
double find_max_diff(double* x, double* pred, int sz1); // Поиск максимальной разности значений после итерации
void copy_int(int* t, int* x, int sz1); // Функция, копирующая массив индексов
void copy_double(double* pred, double* x, int sz1);
// Копирование значений предыдущей итерации для последующего сравнения с новыми значениями
int get_solution(double** m, double* x, int sz1); // Поиск решения системы
double** swap_lines(double** m, int sz1, int* index); // Функция для перестановки строк в соответствии с массивом индексов
void swap(int* a, int* b); // Функция для перестановки в массиве индексов
int* create_int(int sz1); // Создание и инициализация массива индексов
int solve_system(double** m, double* sum, double* x, double* pred, int* index, int sz1);
// Функция, решающая систему без нулей на диагонали
int solve_system_with_zero(double** m, double* sum, double* x, double* pred, int* index, int sz1);
// Функцция, решающая систему с нулями на диагонали
int solve_divergent_system(double** m, double* x, double* pred, int sz1); // Решение системы, для которой не выполнилось ДУС
int solve_convergent_system(double** m, double* x, double* pred, int sz1); // Решение системы, для которой выполнилось ДУС
void copy_double(double* pred, double* x, int sz1)
{ // Копирование значений предыдущей итерации для последующего сравнения с новыми значениями
int i;
for (i=0; i<sz1; i++)
pred[i]=x[i];
}
int solve_divergent_system(double** m, double* x, double* pred, int sz1) // Решение системы, для которой не выполнилось ДУС
{
int iter=0, count=0;
double max=0, max1=max;
while (iter<ITER)
{ // Пока не прошло заданное кол-во итераций
x=iteration(m, x, pred, sz1);
print1(x, sz1);
max=find_max_diff(x, pred, sz1); // Ищем макс. разницу на соседних шагах
printf("%15E\n", max);
if (max<max1)
count++; // Если максимальная разность уменьшается, увеличиваем счётчик
else
count=0;
max1=max;
iter++;
}
if (count<CONST)
{ // Если разность не уменьшилась заданное кол-во раз подряд, значит, система не может быть решена
free(x);
x=0;
}
return (x==0) ? 0 : 1;
}
int solve_convergent_system(double** m, double* x, double* pred, int sz1) // Решение системы, для которой выполнилось ДУС
{
int b=0;
while (b==0) // Пока не найдём решение системы, продолжаем выполнять итерации
{
x=iteration(m, x, pred, sz1);
print1(x, sz1);
if (find_max_diff(x, pred, sz1)<MIN)
return b=1; // Если максимальная разность м/у текущими и предыдущими значениями уже очень мала, выходим из функции
}
}
int* create_int(int sz1) // Создание и инициализация массива индексов
{
int i;
int* mas=(int*) malloc (sz1*sizeof(int));
for (i=0; i<sz1; i++)
mas[i]=i;
return mas;
}
void swap(int* a, int* b){ // Функция для перестановки значений в массиве индексов
int temp=*a;
*a=*b;
*b=temp;
}
double** swap_lines(double** m, int sz1, int* index){ // Функция для перестановки строк в соответствии с массивом индексов
double** m1=(double**) malloc (sz1*sizeof(double*)); // Создаём массив указателей
int i;
for (i=0; i<sz1; i++)
m1[i]=m[index[i]]; // Строки меняются местами
free(m);
return m1;
}
void copy_int(int* t, int* x, int sz1)
{ // Функция, копирующая массив индексов
int i;
for (i=0; i<sz1; i++)
t[i]=x[i];
}
double find_max_diff(double* x, double* pred, int sz1) // Поиск максимальной разности значений после итерации
{
double max=0;
int i;
for (i=0; i<sz1; i++)
if(fabs(x[i]-pred[i])>max)
max=fabs(x[i]-pred[i]);
return max;
}
int solve_system(double** m, double* sum, double* x, double* pred, int* index, int sz1)
{ // Функция, решающая систему без нулей на диагонали
if (check_convergence(m, index, sum, sz1)) // Проверка условия сходимости
return solve_convergent_system(m, x, pred, sz1); // Если ДУС выполняется, просто решаем систему
else
return solve_divergent_system(m, x, pred, sz1); // Если не выполняется, решаем с контролем итераций
}
int transpose_lines(double** m, int* index, int* mix_index, double* sum, int num, int sz1)
{ // Функция для поиска удачной перестановки строк
int b=0;
if (num==sz1-1)
{ // Если перестановка уже выполнилась:
if (check_diagonal(m, index, sz1))
{
if (check_convergence(m, index, sum, sz1)) // Если выполнилось ДУС, значит, перестановка удачная
{
printf("Permutation was found successfully\n");
b=1; // Перестановка удачная
}
else // Если ДУС не выполнилось, то запоминаем данную перестановку для случая, если удачная так и не найдётся
copy_int(mix_index, index, sz1);
}
return b;
}
int i;
for(i=num; i<sz1; i++)
{
swap(&index[num], &index[i]);
b=transpose_lines(m, index, mix_index, sum, num+1, sz1);
if (b==1) return b;
swap(&index[num], &index[i]);
}
}
int solve_system_with_zero(double** m, double* sum, double* x, double* pred, int* index, int sz1)
{ // Функция, решающая систему с нулями на диагонали
int* mix_index=create_int(sz1); // Массив индексов для подходящей подстановки
if (transpose_lines(m, index, mix_index, sum, 0, sz1)==1)
{ // Если найдена нужная перестановка с выполнением ДУС, то переставляем строки и решаем систему
m=swap_lines(m, sz1, index);
print2(m, sz1);
return solve_convergent_system(m, x, pred, sz1);
}
// Если подходящая перестановка с выполнением ДУС не нашлась, то смотрим нули на диагонали
printf("No permutation found'\n");
if (check_diagonal(m, mix_index, sz1))
{ // Если удалось избавиться от нулей на диагонали
m=swap_lines(m, sz1, mix_index); // Меняем строки в соответствии с перестановкой
print2(m, sz1);
free(mix_index);
return solve_divergent_system(m, x, pred, sz1); // Решаем систему с контролем итераций
}
else // Иначе система не может быть решена этим методом
return 0;
}
int get_solution(double** m, double* x, int sz1) // Поиск решения системы
{
int b;
double* pred=create1(sz1); // Создаётся массив, в котором будут храниться корни предыдущей итерации
double* sum=create1(sz1); // Создаётся массив сумм
sum=get_sum(m, sz1);
int* index=create_int(sz1); // Создаётся массив индексов
if (check_diagonal(m, index, sz1)) // Если нет нулей на диагонали, вызываем функцию для решения системы без нулей
b=solve_system(m, sum, x, pred, index, sz1);
else // Если на диагонали есть нули, вызываем функцию для решения системы с нулями на диагонали
b=solve_system_with_zero(m, sum, x, pred, index, sz1);
free(pred);
free(sum);
free(index);
return b;
}
double* iteration(double** m, double* x, double* pred, int sz1) // Итерация
{
int i, j;
double n;
copy_double(pred, x, sz1); // Записываем значения для последующего сравнения
for (i=0; i<sz1; i++)
{ // Для каждого уравнения системы
x[i]=1/m[i][i]; // Записали коэффициент
n=m[i][sz1]; // Записали свободный член
for (j=0; j<sz1; j++)
{
if (i!=j)
n-=m[i][j]*x[j]; // Вычитаем все остальные неизвестные
}
x[i]*=n;
}
return x;
}
double* get_sum(double** m, int sz1) // Функция, считающая сумму эл-тов каждой строки
{
double* s=create1(sz1);
int i, j;
for (i=0; i<sz1; i++)
{
for (j=0; j<sz1; j++)
s[i]+=fabs(m[i][j]); // Считается сумма эл-тов строки
}
return s;
}
int check_convergence(double** m, int* index, double* sum, int sz1) // Функция, проверяющая ДУС
{
int i, count=0;
double d;
for (i=0; i<sz1; i++)
{
d=sum[index[i]]-fabs(m[index[i]][i]); // Из массива сумм вычитаем диагональный элемент
if ((fabs(m[index[i]][i]) >= d)) // Если абс. величина диаг. элемента >= абс. величины суммы оставшихся эл-тов
{
if ((fabs(m[index[i]][i]) > d)) // проверяем, чтобы был хотя бы 1 эл-т, для которого выполнится строгое неравенство
count++; // Считаем, чтобы понять, имеется ли такой элемент
}
else
return 0; // Если хотя бы для одной строки условие не выполняется, то не выполняется и ДУС
}
return (count > 0);
}
int check_diagonal(double** m, int* index, int sz1) // Функция, проверяющая, есть ли на диагонали нули
{
int i;
for (i=0; i<sz1; i++)
if (m[index[i]][i]==0)
return 0; // Если хотя бы один диагональный элемент равен нулю, сразу выходим из функции со значением 0
return 1;
}
void fillMatrix(FILE* f, double** m, int sz1, int sz2)
{ // Функция, считывающая значения коэффициентов из файла и заполняющая ими матрицу
int i, j;
for (i=0; i<sz1; i++)
for (j=0; j<sz2; j++)
fscanf(f, "%lf", &m[i][j]);
}
double* create1(int sz) // Функция выделения памяти под массив решения системы
{
double* m=(double*) malloc (sz*sizeof (double));
int i;
for (i=0; i<sz; i++)
m[i]=0;
return m;
}
double** create2(int sz1, int sz2) // Функция, создающая двумерный массив
{
double** m=(double**) malloc (sz1*sizeof (double*)); // Выделяется память под массив указателей
int i;
for (i=0; i<sz1; i++)
m[i]=(double*) malloc (sz2*sizeof (double)); // Выделяется память под массив элементов типа double
return m;
}
void erase2(double** m, int sz1, int sz2) // Функция, удаляющая из памяти двумерный массив
{
int i;
for (i=0; i<sz1; i++)
free(m[i]); // Очищаются массивы элементов
free(m); // Очищается массив указателей
}
void print1(double* x, int sz1) // Функция печати одномерного массива решений
{
int i;
for (i=0; i<sz1; i++)
printf("x%d=%15E ", i+1, x[i]);
printf("\n");
}
void print2(double** m, int sz1) // Функция печати двумерного массива
{
int i, j;
for (i=0; i<sz1; i++){
for (j=0; j<sz1+1; j++)
printf ("%15E", m[i][j]);
printf ("\n");
}
printf("\n");
}
int main()
{
int sz1, sz2, b;
FILE* f=fopen("SLE for Gauss-Seidel method.txt", "r"); // Открываем файл для чтения
assert(f!=NULL); // Проверяем, открылся ли файл
fscanf(f, "%i %i", &sz1, &sz2); // Считываем размеры матрицы, хранящиеся в 1ой строке файла
double** m=create2(sz1, sz2); // Выделяем память под матрицу
double* x=create1(sz1); // Выделяем память под массив решений
fillMatrix(f, m, sz1, sz2); // Заполняем матрицу значениями из файла
fclose(f);
print2(m, sz1);
if (get_solution(m, x, sz1))
print1(x, sz1);
else
printf("System can't be solved using this method");
free(x);
erase2(m, sz1, sz2);
return 0;
}