diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..920128b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.15) +project(Task01 C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp") + +add_executable(Task01 main.c gauss_algos.h gauss_algos.c) + +find_package(GSL REQUIRED) # See below (2) +target_link_libraries(Task01 GSL::gsl GSL::gslcblas) \ No newline at end of file diff --git a/gauss_algos.c b/gauss_algos.c new file mode 100644 index 0000000..184af22 --- /dev/null +++ b/gauss_algos.c @@ -0,0 +1,75 @@ +#include "gauss_algos.h" + +double *GSL_gauss(int n, double *a, double *b) { + gsl_matrix_view gsl_a = gsl_matrix_view_array(a, n, n); + gsl_vector_view gsl_b = gsl_vector_view_array(b, n); + gsl_vector *gsl_x = gsl_vector_alloc(n); + int s; + gsl_permutation *p = gsl_permutation_alloc(n); + gsl_linalg_LU_decomp(&gsl_a.matrix, p, &s); + gsl_linalg_LU_solve(&gsl_a.matrix, p, &gsl_b.vector, gsl_x); + gsl_permutation_free(p); + double *x = malloc(n * sizeof(double)); + for (int i = 0; i < n; i++) + x[i] = gsl_vector_get(gsl_x, i); + gsl_vector_free(gsl_x); + return x; +} + +double *seq_gauss(int n, double *a, double *b) { + double *x = malloc(sizeof(*x) * n); + // Прямой ход -- O(n^3) + for (int k = 0; k < n - 1; k++) { + // Исключение x_i из строк k+1...n-1 + double pivot = a[k * n + k]; + for (int i = k + 1; i < n; i++) { + // Из уравнения (строки) i вычитается уравнение k + double heads_ratio = a[i * n + k] / pivot; + for (int j = k; j < n; j++) { + a[i * n + j] -= heads_ratio * a[k * n + j]; + } + b[i] -= heads_ratio * b[k]; + } + } + // Обратный ход -- O(n^2) + for (int k = n - 1; k >= 0; k--) { + x[k] = b[k]; + for (int i = k + 1; i < n; i++) + x[k] -= a[k * n + i] * x[i]; + x[k] /= a[k * n + k]; + } + return x; +} + +double *parallel_gauss(int n, double *a, double *b) { + double *x = malloc(sizeof(*x) * n); + // Прямой ход -- O(n^3) + int i, j, k; + omp_set_num_threads(omp_get_max_threads()); + for (k = 0; k < n - 1; k++) { + // Исключение x_i из строк k+1...n-1 + double pivot = a[k * n + k]; + +//#pragma omp parallel for shared(n, a, b, x, pivot, k) private(i, j) default(none) schedule(dynamic) + for (i = k + 1; i < n; i++) { + // Из уравнения (строки) i вычитается уравнение k + double heads_ratio = a[i * n + k] / pivot; +#pragma omp simd + for (j = k; j < n; j++) { + a[i * n + j] -= a[k * n + j] * heads_ratio; + } + b[i] -= heads_ratio * b[k]; + } + } + + // Обратный ход -- O(n^2) + for (k = n - 1; k >= 0; k--) { + x[k] = b[k]; +#pragma omp simd + for (j = k + 1; j < n; j++) + x[k] -= a[k * n + j] * x[j]; + x[k] /= a[k * n + k]; + } + return x; +} + diff --git a/gauss_algos.h b/gauss_algos.h new file mode 100644 index 0000000..029fa18 --- /dev/null +++ b/gauss_algos.h @@ -0,0 +1,13 @@ +#ifndef TASK01_GAUSS_ALGOS_H +#define TASK01_GAUSS_ALGOS_H + #pragma once + #include + #include + #include + double *GSL_gauss(int n, double *a, double *b); + + double *seq_gauss(int n, double *a, double *b); + + double *parallel_gauss(int n, double *a, double *b); + +#endif //TASK01_GAUSS_ALGOS_H diff --git a/gauss_results.txt b/gauss_results.txt new file mode 100644 index 0000000..83f7b9d --- /dev/null +++ b/gauss_results.txt @@ -0,0 +1,28 @@ +Gaussian Elimination (sequential): n 10, mean-time (sec) 0.000002 +Gaussian Elimination (gsl): n 10, mean-time (sec) 0.000003 +Gaussian Elimination (parallel): n 10, mean-time (sec) 0.000002 + +Gaussian Elimination (sequential): n 100, mean-time (sec) 0.001078 +Gaussian Elimination (gsl): n 100, mean-time (sec) 0.000243 +Gaussian Elimination (parallel): n 100, mean-time (sec) 0.001081 + +Gaussian Elimination (sequential): n 200, mean-time (sec) 0.008343 +Gaussian Elimination (gsl): n 200, mean-time (sec) 0.001807 +Gaussian Elimination (parallel): n 200, mean-time (sec) 0.008964 + +Gaussian Elimination (sequential): n 500, mean-time (sec) 0.129559 +Gaussian Elimination (gsl): n 500, mean-time (sec) 0.030214 +Gaussian Elimination (parallel): n 500, mean-time (sec) 0.135428 + +Gaussian Elimination (sequential): n 1000, mean-time (sec) 1.239578 +Gaussian Elimination (gsl): n 1000, mean-time (sec) 0.286485 +Gaussian Elimination (parallel): n 1000, mean-time (sec) 1.174270 + +Gaussian Elimination (sequential): n 2000, mean-time (sec) 10.298086 +Gaussian Elimination (gsl): n 2000, mean-time (sec) 2.707311 +Gaussian Elimination (parallel): n 2000, mean-time (sec) 11.302454 + +Gaussian Elimination (sequential): n 4000, mean-time (sec) 84.347705 +Gaussian Elimination (gsl): n 4000, mean-time (sec) 23.611058 +Gaussian Elimination (parallel): n 4000, mean-time (sec) 80.878901 + diff --git a/main.c b/main.c new file mode 100644 index 0000000..4d0052c --- /dev/null +++ b/main.c @@ -0,0 +1,78 @@ +#include +#include "gauss_algos.h" +#include + +double *generate_matrix(int n) { + double *a = malloc(sizeof(*a) * n * n); + for (int i = 0; i < n; i++) { // Инициализация + // srand(i * (n + 1)); + for (int j = 0; j < n; j++) + a[i * n + j] = rand() % 100 + 1; + } + return a; +} + +double *generate_column(int n) { + double *b = malloc(sizeof(*b) * n); + for (int i = 0; i < n; i++) { + b[i] = rand() % 100 + 1; + } + return b; +} + +int main(int argc, char *argv[]) { + + char need_cmp = 0; + if (argc < 4) { + exit(1); + } + int n = atoi(argv[1]); + int exp_n = atoi(argv[2]); + char *algo_name = argv[3]; + + clock_t start, end; + double clock_sum; + double *(*algo)(int, double *, double *); + switch (algo_name[0]) { + case 's' : { + algo = &seq_gauss; + need_cmp = 1; + break; + } + case 'g' : { + algo = &GSL_gauss; + break; + } + case 'p' : { + algo = ¶llel_gauss; + need_cmp = 1; + break; + } + } + clock_sum = 0; + for (int j = 0; j < exp_n; j++) { + double *a = generate_matrix(n); + double *b = generate_column(n); + start = clock(); + double *x = algo(n, a, b); + end = clock(); + clock_sum += ((double)(end - start)) / CLOCKS_PER_SEC; + + if (need_cmp) { + double *gsl_x = GSL_gauss(n, a, b); + // Сравнение векторов + for (int i = 0; i < n; i++) { + if (fabs(x[i] - gsl_x[i]) > 0.0001) { + fprintf(stderr, "Invalid result: elem %d: %f %f\n", i, x[i], gsl_x[i]); + break; + } + } + free(gsl_x); + } + free(b); + free(a); + free(x); + } + printf("Gaussian Elimination (%s): n %d, mean-time (sec) %.6f\n", algo_name, n, ((double) clock_sum) / (double)exp_n); + return 0; +} diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..8b1c894 --- /dev/null +++ b/start.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +touch gauss_results.txt +> gauss_results.txt +rm gauss +gcc main.c gauss_algos.c -o gauss -lgsl -lgslcblas -fopenmp -O0 +exp_N=10 +for size_N in {10,100,200,500,1000,2000,4000} +do + { + ./gauss "$size_N" "$exp_N" "sequential" + ./gauss "$size_N" "$exp_N" "gsl" + ./gauss "$size_N" "$exp_N" "parallel" + echo ' ' + } >> gauss_results.txt +done