Advertisement
coloriot

HA26

Oct 1st, 2024
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.54 KB | None | 0 0
  1. #include <iostream>
  2. #include <string>
  3.  
  4. // Улучшение класса матриц, с exception, операциями с матрицами и теперь с double вместо int
  5. // теперь с нормальной асимптотикой поиска определителя матрицы
  6.  
  7. using namespace std;
  8.  
  9. // Исключение для разных размерностей матриц
  10. class Error_invalid_size {
  11.     string message;
  12. public:
  13.     Error_invalid_size() : message("Разные размерности!") {}
  14.     ~Error_invalid_size() {}
  15.     void what() {
  16.         cout << message << endl;
  17.     }
  18. };
  19.  
  20. // Исключение для неквадратных матриц
  21. class Error_non_square_matrix {
  22.     string message;
  23. public:
  24.     Error_non_square_matrix() : message("Матрица не квадратная!") {}
  25.     ~Error_non_square_matrix() {}
  26.     void what() {
  27.         cout << message << endl;
  28.     }
  29. };
  30.  
  31. // Исключение для матриц, не являющихся положительно определенными
  32. class Error_not_positive_definite {
  33.     string message;
  34. public:
  35.     Error_not_positive_definite() : message("Матрица не является положительно определенной!") {}
  36.     ~Error_not_positive_definite() {}
  37.     void what() {
  38.         cout << message << endl;
  39.     }
  40. };
  41.  
  42. class Matrix {
  43. private:
  44.     double** matrix;
  45.     int rows;
  46.     int cols;
  47.  
  48.     double my_abs(double x) {
  49.         return x >= 0 ? x : -x;
  50.     }
  51.  
  52.     // Для поиска квадратных корней
  53.     double my_sqrt(double x) {
  54.         if (x < 0) {
  55.             return 0;
  56.         }
  57.         double guess = x / 2.0;
  58.         double epsilon = 1e-10;
  59.         while (my_abs(guess * guess - x) > epsilon) {
  60.             guess = (guess + x / guess) / 2.0;
  61.         }
  62.         return guess;
  63.     }
  64.  
  65. public:
  66.     Matrix(int new_rows, int new_cols) {
  67.         this->rows = new_rows;
  68.         this->cols = new_cols;
  69.         this->matrix = new double*[new_rows];
  70.         for (int i = 0; i < this->rows; ++i) {
  71.             matrix[i] = new double[new_cols];
  72.         }
  73.         for (int i = 0; i < this->rows; ++i) {
  74.             for (int j = 0; j < this->cols; ++j) {
  75.                 matrix[i][j] = 0.0;
  76.             }
  77.         }
  78.     }
  79.  
  80.     Matrix(const Matrix& other) {
  81.         rows = other.rows;
  82.         cols = other.cols;
  83.         matrix = new double*[rows];
  84.         for (int i = 0; i < rows; ++i) {
  85.             matrix[i] = new double[cols];
  86.             for (int j = 0; j < cols; ++j) {
  87.                 matrix[i][j] = other.matrix[i][j];
  88.             }
  89.         }
  90.     }
  91.  
  92.     ~Matrix() {
  93.         for (int i = 0; i < this->rows; ++i) {
  94.             delete[] this->matrix[i];
  95.         }
  96.         delete[] this->matrix;
  97.     }
  98.  
  99.     Matrix operator+ (const Matrix& other) {
  100.         if (this->rows != other.rows || this->cols != other.cols) {
  101.             throw Error_invalid_size();
  102.         }
  103.         Matrix new_matrix(this->rows, this->cols);
  104.         for (int i = 0; i < this->rows; ++i) {
  105.             for (int j = 0; j < this->cols; ++j) {
  106.                 new_matrix.matrix[i][j] = this->matrix[i][j] + other.matrix[i][j];
  107.             }
  108.         }
  109.         return new_matrix;
  110.     }
  111.  
  112.     Matrix operator- (const Matrix& other) {
  113.         if (this->rows != other.rows || this->cols != other.cols) {
  114.             throw Error_invalid_size();
  115.         }
  116.         Matrix new_matrix(this->rows, this->cols);
  117.         for (int i = 0; i < this->rows; ++i) {
  118.             for (int j = 0; j < this->cols; ++j) {
  119.                 new_matrix.matrix[i][j] = this->matrix[i][j] - other.matrix[i][j];
  120.             }
  121.         }
  122.         return new_matrix;
  123.     }
  124.  
  125.     Matrix operator* (const Matrix& other) {
  126.         if (this->cols != other.rows) {
  127.             throw Error_invalid_size();
  128.         }
  129.         Matrix result(this->rows, other.cols);
  130.         for (int i = 0; i < this->rows; ++i) {
  131.             for (int j = 0; j < other.cols; ++j) {
  132.                 result.matrix[i][j] = 0.0;
  133.                 for (int k = 0; k < this->cols; ++k) {
  134.                     result.matrix[i][j] += this->matrix[i][k] * other.matrix[k][j];
  135.                 }
  136.             }
  137.         }
  138.         return result;
  139.     }
  140.  
  141.     Matrix operator* (double scalar) {
  142.         Matrix new_matrix(this->rows, this->cols);
  143.         for (int i = 0; i < this->rows; ++i) {
  144.             for (int j = 0; j < this->cols; ++j) {
  145.                 new_matrix.matrix[i][j] = this->matrix[i][j] * scalar;
  146.             }
  147.         }
  148.         return new_matrix;
  149.     }
  150.  
  151.     friend Matrix operator* (double scalar, const Matrix& mat) {
  152.         Matrix new_matrix(mat.rows, mat.cols);
  153.         for (int i = 0; i < mat.rows; ++i) {
  154.             for (int j = 0; j < mat.cols; ++j) {
  155.                 new_matrix.matrix[i][j] = scalar * mat.matrix[i][j];
  156.             }
  157.         }
  158.         return new_matrix;
  159.     }
  160.  
  161.     // Произведение Адамара
  162.     Matrix operator% (const Matrix& other) {
  163.         if (this->rows != other.rows || this->cols != other.cols) {
  164.             throw Error_invalid_size();
  165.         }
  166.         Matrix new_matrix(this->rows, this->cols);
  167.         for (int i = 0; i < this->rows; ++i) {
  168.             for (int j = 0; j < this->cols; ++j) {
  169.                 new_matrix.matrix[i][j] = this->matrix[i][j] * other.matrix[i][j];
  170.             }
  171.         }
  172.         return new_matrix;
  173.     }
  174.  
  175.     Matrix transpose() {
  176.         Matrix new_matrix(this->cols, this->rows);
  177.         for (int i = 0; i < this->rows; ++i) {
  178.             for (int j = 0; j < this->cols; ++j) {
  179.                 new_matrix.matrix[j][i] = this->matrix[i][j];
  180.             }
  181.         }
  182.         return new_matrix;
  183.     }
  184.  
  185.     double determinant() {
  186.         if (this->rows != this->cols) {
  187.             throw Error_non_square_matrix();
  188.         }
  189.         int n = this->rows;
  190.         // Сохраняем исходные данные
  191.         double** mat_copy = new double*[n];
  192.         for (int i = 0; i < n; i++) {
  193.             mat_copy[i] = new double[n];
  194.             for (int j = 0; j < n; j++) {
  195.                 mat_copy[i][j] = this->matrix[i][j];
  196.             }
  197.         }
  198.  
  199.         double det = 1.0;
  200.         int sign = 1;
  201.  
  202.         for (int k = 0; k < n; k++) {
  203.             // Частичный поворот для численной стабильности
  204.             double max = my_abs(mat_copy[k][k]);
  205.             int maxRow = k;
  206.             for (int i = k + 1; i < n; i++) {
  207.                 if (my_abs(mat_copy[i][k]) > max) {
  208.                     max = my_abs(mat_copy[i][k]);
  209.                     maxRow = i;
  210.                 }
  211.             }
  212.             // Если опорный элемент равен нулю, то определитель равен нулю
  213.             if (mat_copy[maxRow][k] == 0) {
  214.                 det = 0.0;
  215.                 break;
  216.             }
  217.             // Swap rows if needed
  218.             if (maxRow != k) {
  219.                 double* temp = mat_copy[k];
  220.                 mat_copy[k] = mat_copy[maxRow];
  221.                 mat_copy[maxRow] = temp;
  222.                 sign *= -1;
  223.             }
  224.  
  225.             // Исключяем ниже точки разворота
  226.             for (int i = k + 1; i < n; i++) {
  227.                 double factor = mat_copy[i][k] / mat_copy[k][k];
  228.                 mat_copy[i][k] = 0.0;
  229.                 for (int j = k + 1; j < n; j++) {
  230.                     mat_copy[i][j] -= factor * mat_copy[k][j];
  231.                 }
  232.             }
  233.         }
  234.  
  235.         if (det != 0.0) {
  236.             // Умножаем диагональные элементы
  237.             for (int i = 0; i < n; i++) {
  238.                 det *= mat_copy[i][i];
  239.             }
  240.             det *= sign;
  241.         }
  242.  
  243.         // Чистим память
  244.         for (int i = 0; i < n; i++) {
  245.             delete[] mat_copy[i];
  246.         }
  247.         delete[] mat_copy;
  248.  
  249.         return det;
  250.     }
  251.  
  252.     // След матрицы
  253.     double trace() {
  254.         if (this->rows != this->cols) {
  255.             throw Error_non_square_matrix();
  256.         }
  257.         double sum = 0.0;
  258.         for (int i = 0; i < this->rows; ++i) {
  259.             sum += this->matrix[i][i];
  260.         }
  261.         return sum;
  262.     }
  263.  
  264.     // Разложение Холецкого
  265.     Matrix cholesky() {
  266.         if (this->rows != this->cols) {
  267.             throw Error_non_square_matrix();
  268.         }
  269.         int n = this->rows;
  270.         Matrix L(n, n);
  271.         for (int i = 0; i < n; i++) {
  272.             for (int j = 0; j <= i; j++) {
  273.                 double sum = 0.0;
  274.                 if (j == i) {
  275.                     for (int k = 0; k < j; k++) {
  276.                         sum += L.matrix[j][k] * L.matrix[j][k];
  277.                     }
  278.                     double val = this->matrix[j][j] - sum;
  279.                     if (val <= 0) {
  280.                         throw Error_not_positive_definite();
  281.                     }
  282.                     L.matrix[j][j] = my_sqrt(val);
  283.                 } else {
  284.                     for (int k = 0; k < j; k++) {
  285.                         sum += L.matrix[i][k] * L.matrix[j][k];
  286.                     }
  287.                     L.matrix[i][j] = (1.0 / L.matrix[j][j]) * (this->matrix[i][j] - sum);
  288.                 }
  289.                 L.matrix[j][i] = 0.0; // Обеспечиваем нули в верхней треугольной части
  290.             }
  291.         }
  292.         return L;
  293.     }
  294.  
  295.     double get(int i, int j) const {
  296.         if (i < 0 || i >= this->rows || j < 0 || j >= this->cols) {
  297.             throw std::out_of_range("Индекс вне диапазона!");
  298.         }
  299.         return this->matrix[i][j];
  300.     }
  301.  
  302.     void set(int i, int j, double value) {
  303.         if (i < 0 || i >= this->rows || j < 0 || j >= this->cols) {
  304.             throw std::out_of_range("Индекс вне диапазона!");
  305.         }
  306.         this->matrix[i][j] = value;
  307.     }
  308.  
  309.     // Поиск обратной матрицы
  310.     Matrix invert() {
  311.         if (this->rows != this->cols) {
  312.             throw Error_non_square_matrix();
  313.         }
  314.         int n = this->rows;
  315.         Matrix aug(n, 2 * n);
  316.         // Расширенная матрица [A | I]
  317.         for (int i = 0; i < n; i++) {
  318.             for (int j = 0; j < n; j++) {
  319.                 aug.set(i, j, this->get(i, j));
  320.             }
  321.             for (int j = n; j < 2 * n; j++) {
  322.                 aug.set(i, j, (i == j - n) ? 1.0 : 0.0);
  323.             }
  324.         }
  325.         // Исключения по Гауссу-Джордану
  326.         for (int i = 0; i < n; i++) {
  327.             // Точка опоры
  328.             double pivot = aug.get(i, i);
  329.             if (pivot == 0) {
  330.                 throw std::runtime_error("Матрица является вырожденной и не может быть инвертирована.");
  331.             }
  332.             // Нормализуем
  333.             for (int j = 0; j < 2 * n; j++) {
  334.                 aug.set(i, j, aug.get(i, j) / pivot);
  335.             }
  336.             // Убираем другие строки
  337.             for (int k = 0; k < n; k++) {
  338.                 if (k != i) {
  339.                     double factor = aug.get(k, i);
  340.                     for (int j = 0; j < 2 * n; j++) {
  341.                         aug.set(k, j, aug.get(k, j) - factor * aug.get(i, j));
  342.                     }
  343.                 }
  344.             }
  345.         }
  346.         // Извлекаем обратную матрицу
  347.         Matrix inv(n, n);
  348.         for (int i = 0; i < n; i++) {
  349.             for (int j = n; j < 2 * n; j++) {
  350.                 inv.set(i, j - n, aug.get(i, j));
  351.             }
  352.         }
  353.         return inv;
  354.     }
  355.  
  356.     void print() const {
  357.         for (int i = 0; i < this->rows; ++i) {
  358.             for (int j = 0; j < this->cols; ++j) {
  359.                 cout << matrix[i][j] << ' ';
  360.             }
  361.             cout << '\n';
  362.         }
  363.     }
  364. };
  365.  
  366. int main() {
  367.     try {
  368.         Matrix mat1(2, 2);
  369.         mat1.set(0, 0, 4.0);
  370.         mat1.set(0, 1, 12.0);
  371.         mat1.set(1, 0, 12.0);
  372.         mat1.set(1, 1, 37.0);
  373.  
  374.         Matrix mat2(2, 2);
  375.         mat2.set(0, 0, 3.0);
  376.         mat2.set(0, 1, 4.0);
  377.         mat2.set(1, 0, 5.0);
  378.         mat2.set(1, 1, 6.0);
  379.  
  380.         Matrix sum = mat1 + mat2;
  381.         cout << "Сумма:\n";
  382.         sum.print();
  383.  
  384.         Matrix diff = mat1 - mat2;
  385.         cout << "Разность:\n";
  386.         diff.print();
  387.  
  388.         Matrix prod = mat1 * mat2;
  389.         cout << "Умножение:\n";
  390.         prod.print();
  391.  
  392.         Matrix scalar_mul = mat1 * 2.0;
  393.         cout << "Скалярное произведение на 2:\n";
  394.         scalar_mul.print();
  395.  
  396.         Matrix hadamard = mat1 % mat2;
  397.         cout << "Произведение Адамара:\n";
  398.         hadamard.print();
  399.  
  400.         Matrix transposed = mat1.transpose();
  401.         cout << "Транспонирование:\n";
  402.         transposed.print();
  403.  
  404.         double det = mat1.determinant();
  405.         cout << "Определитель: " << det << endl;
  406.  
  407.         double tr = mat1.trace();
  408.         cout << "След: " << tr << endl;
  409.  
  410.         Matrix chol = mat1.cholesky();
  411.         cout << "Разложение Холецкого:\n";
  412.         chol.print();
  413.  
  414.         Matrix inv = mat1.invert();
  415.         cout << "Обратная матрица:\n";
  416.         inv.print();
  417.  
  418.     } catch (Error_invalid_size& e) {
  419.         e.what();
  420.     } catch (Error_non_square_matrix& e) {
  421.         e.what();
  422.     } catch (Error_not_positive_definite& e) {
  423.         e.what();
  424.     } catch (std::exception& e) {
  425.         cout << e.what() << endl;
  426.     }
  427.     return 0;
  428. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement