Advertisement
Guest User

Untitled

a guest
Oct 14th, 2019
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.46 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <string.h>
  5.  
  6. #define data_t double
  7. #define MODIFIER_A "%4.01lf"
  8. #define MODIFIER_B "%9.05lf"
  9.  
  10.  
  11. void print_system(data_t* A, data_t* B, size_t matrix_size) {
  12.     for (size_t i = 0; i < matrix_size; ++i) {
  13.         for (size_t j = 0; j < matrix_size; ++j) {
  14.             printf(MODIFIER_A " ", A[matrix_size * i + j]);
  15.         }
  16.         printf(" |" MODIFIER_B "\n", B[i]);
  17.     }
  18.     printf("\n");
  19. }
  20.  
  21. void print_matrix(data_t* A, size_t matrix_size) {
  22.     for (size_t i = 0; i < matrix_size; ++i) {
  23.         for (size_t j = 0; j < matrix_size; ++j) {
  24.             printf(MODIFIER_A " ", A[matrix_size * i + j]);
  25.         }
  26.         printf("\n");
  27.     }
  28.     printf("\n");
  29. }
  30.  
  31. void print_vector(data_t* B, size_t matrix_size) {
  32.     for (size_t i = 0; i < matrix_size; ++i) {
  33.         printf(MODIFIER_B " ", B[i]);
  34.     }
  35.     printf("\n");
  36. }
  37.  
  38. void swap(data_t* x, data_t* y) {
  39.     data_t buffer = *x;
  40.     *x = *y;
  41.     *y = buffer;
  42. }
  43.  
  44. // Добавить к одной строке другую, применяется в случае нуля на диагонали
  45. void swap_rows_inplace(data_t* A, size_t matrix_size, size_t row_first_index, size_t row_second_index) {
  46.     data_t* row_first = A + matrix_size * row_first_index;
  47.     data_t* row_second = A + matrix_size * row_second_index;
  48.  
  49.     // cache friendly optimization for sse2 set of instructions
  50.     for (size_t index = 0; index < matrix_size; ++index) {
  51.         swap(row_first + index, row_second + index);
  52.     }
  53. }
  54.  
  55.  
  56. void gauss_forward(data_t *A, data_t *B, size_t matrix_size) {
  57.     for (size_t row_index = 0; row_index < matrix_size; ++row_index) {
  58.         if (A[matrix_size * row_index + row_index] == 0) {
  59.  
  60.             for (size_t next_row_index = row_index + 1; next_row_index < matrix_size; ++next_row_index) {
  61.                 if (A[matrix_size * next_row_index + row_index] != 0) {
  62.                     swap_rows_inplace(A, matrix_size, row_index, next_row_index);
  63.                     swap(B + row_index, B + next_row_index);
  64.                     break;
  65.                 }
  66.             }
  67.  
  68.             if (A[matrix_size * row_index + row_index] == 0) {
  69.                 printf("Oops, det A = 0\n");
  70.                 exit(EXIT_FAILURE);
  71.             }
  72.  
  73.         }
  74.  
  75.         for (size_t next_row_index = row_index + 1; next_row_index < matrix_size; ++next_row_index) {
  76.             data_t multiplier = A[next_row_index * matrix_size + row_index] / A[row_index * matrix_size + row_index];
  77.  
  78.             for (size_t k = row_index; k < matrix_size; ++k) {
  79.                 A[next_row_index * matrix_size + k] -= A[row_index * matrix_size + k] * multiplier;
  80.             }
  81.  
  82.             B[next_row_index] -= multiplier * B[row_index];
  83.         }
  84.  
  85.     }
  86. }
  87.  
  88. void gauss_backward(data_t* A, data_t* B, size_t matrix_size) {
  89.     for (int row_index = (int)matrix_size - 1; row_index >= 0; --row_index) {
  90.         data_t diag_elem = A[row_index * matrix_size + row_index];
  91.  
  92.         A[row_index * matrix_size + row_index] /= diag_elem;
  93.         B[row_index] /= diag_elem;
  94.  
  95.         for (int prev_row_index = row_index - 1; prev_row_index >= 0; --prev_row_index) {
  96.             data_t local_mul =  A[prev_row_index * matrix_size + row_index];
  97.             A[prev_row_index * matrix_size + row_index] = 0;
  98.             B[prev_row_index] -= B[row_index] * local_mul;
  99.         }
  100.     }
  101. }
  102.  
  103. void gauss_solve(data_t* A, data_t* B, size_t matrix_size) {
  104.     gauss_forward(A, B, matrix_size);
  105.     gauss_backward(A, B, matrix_size);
  106. }
  107.  
  108. void build_LD(data_t* A, size_t matrix_size, data_t* LD) {
  109.     for (size_t i = 0; i < matrix_size; ++i) {
  110.         for (size_t j = 0; j <= i; ++j) {
  111.             LD[i * matrix_size + j] = A[i * matrix_size + j];
  112.         }
  113.         for (size_t j = i + 1; j < matrix_size; ++j) {
  114.             LD[i * matrix_size + j] = 0;
  115.         }
  116.     }
  117. }
  118.  
  119. void build_U(data_t* A, size_t matrix_size, data_t* U) {
  120.     for (size_t i = 0; i < matrix_size; ++i) {
  121.         for (size_t j = 0; j <= i; ++j) {
  122.             U[i * matrix_size + j] = 0;
  123.         }
  124.         for (size_t j = i + 1; j < matrix_size; ++j) {
  125.             U[i * matrix_size + j] = A[i * matrix_size + j];
  126.         }
  127.     }
  128. }
  129.  
  130. void multiply_matrix_to_vector_inplace(data_t* A, data_t* B, size_t matrix_size) {
  131.     data_t* result = (data_t*) malloc (sizeof(data_t) * matrix_size);
  132.     if (result == NULL) {
  133.         printf("Not enough memory\n");
  134.         exit(EXIT_FAILURE);
  135.     }
  136.  
  137.     for (size_t i = 0; i < matrix_size; ++i) {
  138.         result[i] = 0;
  139.         for (size_t j = 0; j < matrix_size; ++j) {
  140.             result[i] += A[i * matrix_size + j] * B[j];
  141.         }
  142.     }
  143.     memcpy(B, result, sizeof(data_t) * matrix_size);
  144.     free(result);
  145. }
  146.  
  147. void solve_ld_system_inplace(data_t* LD, data_t* B, size_t matrix_size) {
  148.     for (size_t row_index = 0; row_index < matrix_size; ++row_index) {
  149.         data_t diag_elem = LD[row_index * matrix_size + row_index];
  150.         LD[row_index * matrix_size + row_index] /= diag_elem;
  151.         B[row_index] /= diag_elem;
  152.  
  153.         for (size_t next_row_index = row_index + 1;
  154.                 next_row_index < matrix_size; ++next_row_index) {
  155.  
  156.             data_t local_mul = LD[next_row_index * matrix_size + row_index];
  157.             LD[next_row_index * matrix_size + row_index] = 0;
  158.             B[next_row_index] -= B[row_index] * local_mul;
  159.         }
  160.     }
  161. }
  162.  
  163. void zeidel_solve(data_t* A, data_t* B, size_t matrix_size, data_t eps) {
  164.     data_t* U = (data_t*) malloc (sizeof(data_t) * matrix_size * matrix_size);
  165.     data_t* LD = (data_t*) malloc (sizeof(data_t) * matrix_size * matrix_size);
  166.     data_t* LD_buffer = (data_t*) malloc (sizeof(data_t) * matrix_size * matrix_size);
  167.  
  168.     data_t* x_current = (data_t*) malloc (sizeof(data_t) * matrix_size);
  169.     data_t* x_buffer = (data_t*) malloc (sizeof(data_t) * matrix_size);
  170.  
  171.     if (U == NULL || LD == NULL || x_current == NULL || x_buffer == NULL) {
  172.         free(U);
  173.         free(LD);
  174.         free(x_current);
  175.         free(x_buffer);
  176.         printf("Not enough memory\n");
  177.         exit(EXIT_FAILURE);
  178.     }
  179.  
  180.     // Начинаем с приближения единицами
  181.     for (size_t i = 0; i < matrix_size; ++i) {
  182.         x_current[i] = 0;
  183.     }
  184.  
  185.     build_LD(A, matrix_size, LD);
  186.     build_U(A, matrix_size, U);
  187.  
  188.     for (;;) {
  189.         memcpy(x_buffer, x_current, sizeof(data_t) * matrix_size);
  190.  
  191.         multiply_matrix_to_vector_inplace(U, x_buffer, matrix_size);
  192.  
  193.         // x_buffer = -Ux
  194.         for (size_t i = 0; i < matrix_size; ++i) {
  195.             x_buffer[i] = -x_buffer[i] + B[i];
  196.         }
  197.         // x_buffer = -Ux + B
  198.  
  199.         memcpy(LD_buffer, LD, sizeof(data_t) * matrix_size * matrix_size);
  200.         solve_ld_system_inplace(LD_buffer, x_buffer, matrix_size);
  201.  
  202.         // x_buffer = (L + D) ^ {-1} * (-Ux + B)
  203.  
  204.         data_t diff_norm = 0;
  205.         for (size_t i = 0; i < matrix_size; ++i) {
  206.             diff_norm += (x_buffer[i] - x_current[i]) * (x_buffer[i] - x_current[i]);
  207.         }
  208.  
  209.         if (diff_norm < eps * eps) {
  210.             memcpy(B, x_buffer, sizeof(data_t) * matrix_size);
  211.  
  212.             free(U);
  213.             free(LD);
  214.             free(LD_buffer);
  215.             free(x_buffer);
  216.             free(x_current);
  217.             break;
  218.         }
  219.         memcpy(x_current, x_buffer, sizeof(data_t) * matrix_size);
  220.     }
  221.  
  222.  
  223. }
  224.  
  225. int main(void) {
  226.     size_t matrix_size = 20;
  227.     data_t* A = (data_t*) malloc (sizeof(data_t) * matrix_size * matrix_size);
  228.     data_t* B = (data_t*) malloc (sizeof(data_t) * matrix_size);
  229.  
  230.     if (A == NULL || B == NULL) {
  231.         printf("Not enough memory\n");
  232.         free(A);
  233.         free(B);
  234.         return EXIT_FAILURE;
  235.     }
  236.  
  237.     // Заполняем А
  238.     A[0 * matrix_size + 0] = 1;
  239.     for (size_t i = 1; i + 1 < matrix_size; ++i) {
  240.         A[i * matrix_size + i] = -2; // Главная диагональ
  241.         A[i * matrix_size + i + 1] = 1; // Над главной диагональю
  242.         A[i * matrix_size + i - 1] = 1; // под главной диагональю
  243.     }
  244.  
  245.     for (size_t i = 0; i < matrix_size; ++i) {
  246.         A[(matrix_size - 1) * matrix_size + i] = 1;
  247.     }
  248.  
  249.     // Заполняем В
  250.     B[0] = 1;
  251.     for (size_t i = 1; i + 1 < matrix_size; ++i) {
  252.         B[i] = 2.0 / (i + 1) / (i + 1);
  253.     }
  254.     B[matrix_size - 1] = -19.0 / 3;
  255.  
  256.     printf("Linear system:\n");
  257.     print_system(A, B, matrix_size);
  258.  
  259.     // print_system(A, B, matrix_size); // диагональная после прямого хода гаусса
  260.     data_t* A_copy = (data_t*) malloc (sizeof(data_t) * matrix_size * matrix_size);
  261.     data_t* B_copy = (data_t*) malloc (sizeof(data_t) * matrix_size);
  262.  
  263.     if (A_copy == NULL || B_copy == NULL) {
  264.         printf("not enough memory\n");
  265.         free(A);
  266.         free(A_copy);
  267.         free(B);
  268.         free(B_copy);
  269.     }
  270.  
  271.  
  272.  
  273.     memcpy(A_copy, A, sizeof(data_t) * matrix_size * matrix_size);
  274.     memcpy(B_copy, B, sizeof(data_t) * matrix_size);
  275.  
  276.     gauss_solve(A_copy, B_copy, matrix_size);
  277.     printf("Gauss solution:\n");
  278.     print_vector(B_copy, matrix_size);
  279.     printf("\n");
  280.  
  281.     memcpy(A_copy, A, sizeof(data_t) * matrix_size * matrix_size);
  282.     memcpy(B_copy, B, sizeof(data_t) * matrix_size);
  283.  
  284.     zeidel_solve(A_copy, B_copy, matrix_size, 0.001);
  285.     printf("Zeidel solution:\n");
  286.     print_vector(B_copy, matrix_size);
  287.     printf("\n");
  288.  
  289.  
  290.  
  291.     free(A);
  292.     free(B);
  293.     free(A_copy);
  294.     free(B_copy);
  295.  
  296.     return EXIT_SUCCESS;
  297. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement