Advertisement
VladimirKostovsky

ChM_lab1

Nov 6th, 2024
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 35.62 KB | None | 0 0
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <fstream>
  4. #include <iomanip>
  5. #include <iostream>
  6. #include <vector>
  7. #include <string>
  8. #include <sstream>
  9. #include <cmath>
  10. #define EPS 1E-14
  11.  
  12. double dabs(double _) { return _ > 0 ? _ : -_; }
  13.  
  14. // Матрица в профильном формате
  15. template<typename T>
  16. struct SkylineStorageMatrix
  17. {
  18.     std::vector<int> ia; // индексы начала каждого столбца
  19.     std::vector<T> al;   // элементы ниже глав. диагонали
  20.     std::vector<T> au;   // элементы выше глав. диагонали
  21.     std::vector<T> di;   // элементы глав. диагонали
  22. };
  23.  
  24. // Считать матрицу в профильном формате
  25. template<typename T>
  26. void readSkyline(std::istream& from, SkylineStorageMatrix<T>& to)
  27. {
  28.     int n;
  29.     from >> n;                        // размер матрицы
  30.     to.ia.resize(n + 1);              // резерв места для индексов (n+1)
  31.     for (int i = 0; i < n + 1; i++)
  32.     {
  33.         from >> to.ia[i];         // индексы начала каждого столбца
  34.     }
  35.  
  36.     int k = to.ia[n];             // количество ненулевых элементов
  37.     to.al.resize(k);              // резерв места для элементов нижнего треугольника
  38.     for (int i = 0; i < k; i++)
  39.     {
  40.         from >> to.al[i];         // записываем элементы ниже глав. диагонали
  41.     }
  42.     to.au.resize(k);              // резерв места для элементов выше глав. диагонали
  43.     for (int i = 0; i < k; i++)
  44.     {
  45.         from >> to.au[i];         // записываем элементы выше глав. диагонали
  46.     }
  47.  
  48.     to.di.resize(n);
  49.     for (int i = 0; i < n; i++)   // резерв места для элементов глав. диагонали
  50.     {
  51.         from >> to.di[i];         // записываем элементы глав. диагонали
  52.     }
  53. }
  54.  
  55. // Сконвертировать матрицу в профильном формате в квадратную
  56. template<typename T>
  57. void skylineToSquare(SkylineStorageMatrix<T>& a, std::vector<std::vector<T>>& s)
  58. {  
  59.     // вычисление кол-ва ненулевых элементов в строке i
  60.     #define elementsInLine(i) (a.ia[i + 1] - a.ia[i])
  61.  
  62.     // изменяем размер матрицы в соотв. с размером главной диагонали
  63.     s.resize(a.di.size());
  64.  
  65.     // заполнение матрицы нулями
  66.     for (unsigned int i = 0; i < a.di.size(); i++)
  67.     {
  68.         s[i].resize(a.di.size());   // устанавливаем размер каждой строки
  69.         for (unsigned int j = 0; j < a.di.size(); j++)
  70.         {
  71.             s[i][j] = (T)0;         // каждый элемент приравниваем к 0
  72.         }
  73.     }
  74.  
  75.     // заполнение главной диагонали матрицы значениями из вектора
  76.     for (unsigned int i = 0; i < a.di.size(); i++)
  77.     {
  78.         s[i][i] = a.di[i];
  79.     }
  80.  
  81.     // заполнение элементов ниже и выше глав. диагонали
  82.     for (unsigned int i = 1; i < a.di.size(); i++)
  83.     {
  84.         // считаем смещение для заполнения элементов ниже глав. диагонали
  85.         int offset = i - elementsInLine(i);
  86.         for (int j = 0; j < elementsInLine(i); j++)
  87.         {
  88.             s[i][offset + j] = a.al[a.ia[i] + j];  // заполнение элементов ниже глав. диагонали
  89.                                                    // это все классно, заполняем симметричные
  90.             s[offset + j][i] = a.au[a.ia[i] + j];  // заполнение элементов выше глав. диагонали
  91.         }
  92.     }
  93.     // больше не считаем ненулевые элементы
  94.     #undef elementsInLine
  95. }
  96.  
  97.  // Считать вектор
  98. template<typename T>
  99. void readVector(std::istream& from, std::vector<T>& to)
  100. {
  101.     int n;         // берем размерность вектора
  102.     from >> n;
  103.     to.resize(n);  // изменяем размер вектора to
  104.     for (int i = 0; i < n; i++)
  105.     {
  106.         from >> to[i]; // передаем параметры с ввода в ячейки массива
  107.     }
  108. }
  109.  
  110. // Распечатать квадратную матрицу
  111. template<typename T>
  112. void printMatrix(const std::vector<std::vector<T>> a)
  113. {
  114.     for (unsigned int i = 0; i < a.size(); i++)  // обычный вывод таблицы
  115.     {
  116.         for (unsigned int j = 0; j < a.size(); j++)
  117.         {
  118.             std::cout << std::setw(20) << a[i][j];
  119.         }
  120.         std::cout << std::endl;
  121.     }
  122. }
  123.  
  124. // Распечатать матрицу в профильном формате
  125. template<typename T>
  126. void printSkyline(SkylineStorageMatrix<T>& a)
  127. {
  128.     std::vector<std::vector<T>> s;
  129.     skylineToSquare(a, s); // берем 4 вектора, выводим их в разные строки.
  130.     printMatrix(s);        // выводим как матрицу
  131. }
  132.  
  133.  
  134. // LU(sq)-разложение матрицы в профильном формате
  135. template<typename T, typename T2=T>                // создание двух типов для быстрого переключения
  136. bool LusqSkyline(SkylineStorageMatrix<T>& a)
  137. {
  138.     // Присвоить dst значение корня из val.
  139.     // Если val <= 0, вернуть false из текущей подпрограммы.
  140.     // проверка на отрицательный корень
  141.     #define _sqrt(dst, val) { double underSqrt = (double)(val); if (underSqrt <= 0) return false; dst = (T)sqrt(underSqrt); }
  142.  
  143.     // Количество элементов в i'ой строке/столбце (ненулевых элементов)
  144.     #define elementsInLine(i) (a.ia[i + 1] - a.ia[i])
  145.  
  146.     // Первая строка матрицы
  147.     _sqrt(a.di[0], a.di[0]); // d_1 = sqrt(a_11);
  148.                              // вычисляется квадратный корень из первого элемента диагонали
  149.                              // Если этот элемент меньше или равен нулю, функция завершится с возвратом false.
  150.     for (unsigned int i = 1; i < a.di.size(); i++)
  151.     {   // Нужны ненулевые элементы первой строки
  152.         // i'ый элемент первой строки ненулевой <=> i'ый столбец содержит i элементов
  153.         if (elementsInLine(i) == i)
  154.         {
  155.             a.au[a.ia[i]] = a.au[a.ia[i]] / a.di[0]; // U_1i = a_1i/q1
  156.             // a.au[a.ia[i]] - что это.
  157.         }
  158.     }
  159.  
  160.     // Обход по строкам матрицы
  161.     for (unsigned int i = 1; i < a.di.size(); i++)
  162.     {
  163.         if (a.al.size())
  164.         {
  165.             // l_ij = (a_ij - \sum_{k=1}{j-1} l_ik * u_kj) / d_j
  166.             // Для вычисления j'го элемента i'ой строки, необходимо найти
  167.             // сумму произведений первых j-1 элементов i'ой строки на
  168.             // соответствующие первые j-1 элементов j'го столбца.
  169.             // Затем вычесть её из a_ij и полученную разность поделить на a_jj.
  170.             // "Легко заметить, что подобное преобразование сохраняет портрет матрицы"
  171.  
  172.             unsigned int alStartIndex = a.ia[i];                   // индекс первого ненулевого элемента i'ой строки в массиве al
  173.             unsigned int alEndIndex = a.ia[i] + elementsInLine(i); // индекс последнего ненулевого элемента (????)
  174.             unsigned int j = i - elementsInLine(i);                // индекс текущего столбца
  175.  
  176.             // До первого ненулевого элемента не было ненулевых элементов (??????)
  177.             a.al[alStartIndex] = a.al[alStartIndex] / a.di[j];     // нормализация первого элемента
  178.             alStartIndex++;                                        // переход к сл. элементу строки
  179.             j++;                                                   // переход к сл. столбцу
  180.  
  181.             // Основной цикл
  182.             for (unsigned int alIndex = alStartIndex; alIndex < alEndIndex; alIndex++, j++)
  183.             {
  184.                 T sum = (T)0;                                      // Инициализация суммы
  185.                 unsigned int elementsInLineI = elementsInLine(i);  // Количество ненулевых элементов в строке i
  186.                 unsigned int elementsInColJ = elementsInLine(j);   // Количество ненулевых элементов в столбце j
  187.  
  188.                 // Для каждого ненулевого элемента из [alIndex...alEndIndex]
  189.                 // вычисляем сумму произведений элементов l_ik и u_kj
  190.                 // l_ik — элемент нижней треугольной матрицы, соответствующий текущему элементу строки.
  191.                 // u_kj — элемент верхней треугольной матрицы, соответствующий текущему элементу столбца.
  192.                 // Если индекс k меньше количества ненулевых элементов
  193.                 // в текущем столбце или строке, то получаем соответствующие значения,
  194.                 // иначе присваиваем 0.
  195.  
  196.                 // Цикл для вычисления суммы произведений
  197.                 for (unsigned int k = 0; k < j; k++)
  198.                 {
  199.                     T l_ik = (k < i - elementsInLineI) ? (T)0 : a.al[a.ia[i] + (k - (i - elementsInLineI))];
  200.                     T u_kj = (k < j - elementsInColJ) ? (T)0 : a.au[a.ia[j] + (k - (j - elementsInColJ))];
  201.                     sum += l_ik * u_kj;  
  202.                 }
  203.                 // Обновляем элемент alIndex
  204.                 a.al[alIndex] = (a.al[alIndex] - sum) / a.di[j];
  205.             }
  206.         }
  207.  
  208.         // d_i = sqrt(d_i - \sum_{k=1}{i-1} l_ik * u_ki) // отладка
  209.         // Повторение основного цикла для T2
  210.        
  211.         {
  212.             T2 sum = (T2)0;
  213.             unsigned int elementsInLineI = elementsInLine(i); // Получаем количество ненулевых элементов в строке i
  214.             for (unsigned int k = 0; k < i; k++)
  215.             {
  216.                 T l_ik = (k < i - elementsInLineI) ? (T)0 : a.al[a.ia[i] + (k - (i - elementsInLineI))];
  217.                 T l_ki = (k < i - elementsInLineI) ? (T)0 : a.au[a.ia[i] + (k - (i - elementsInLineI))];
  218.                 sum += (T2)l_ik * (T2)l_ki;  // Приведение к типу T2 для суммирования
  219.             }
  220.             // printf("%d %lf\n", i, sum); // отладка
  221.             _sqrt(a.di[i], a.di[i] - sum); // обновляем диагональный элемент
  222.         }
  223.  
  224.         if (a.au.size())  // проверка на наличие элементов в верхней матрице
  225.         {
  226.             // u_ij = (a_ij - \sum_{k=1}{i-1} l_ik * u_kj) / d_j
  227.             // То же самое, что l_ij, только писать нужно в al (не последовательно) и сумма по k до i,
  228.             // и делить на di[i]
  229.  
  230.             for (unsigned int j = i + 1; j < a.di.size(); j++)
  231.             {
  232.                 if (i >= j - elementsInLine(j)) // Проверка, что текущий индекс i не выходит за пределы j
  233.                                                 // т.к матрица квадратная
  234.                 {
  235.                     T2 sum = (T2)0;
  236.                     unsigned int elementsInLineI = elementsInLine(i); // количество ненулевых элементов в строке
  237.                     unsigned int elementsInColJ = elementsInLine(j); // количество ненулевых элементов в столбце
  238.                     for (unsigned int k = 0; k < i; k++)
  239.                     {
  240.                         T l_ik = (k < i - elementsInLineI) ? (T)0 : a.al[a.ia[i] + (k - (i - elementsInLineI))];
  241.                         T u_kj = (k < j - elementsInColJ) ? (T)0 : a.au[a.ia[j] + (k - (j - elementsInColJ))];
  242.                         sum += (T2)l_ik * (T2)u_kj;
  243.                     }
  244.  
  245.                     unsigned int auIndex = a.ia[j] + (i - (j - elementsInLine(j))); // Вычислим индекс для записи в верхнюю треугольную матрицу
  246.                     a.au[auIndex] = (a.au[auIndex] - sum) / a.di[i]; // Обновляем значение в верхней треугольной матрице
  247.                 }
  248.             }
  249.         }
  250.     }
  251.  
  252.     #undef elementsInLine
  253.     #undef _sqrt
  254.     // printSkyline(a); // отладка
  255.     return true;
  256. }
  257.  
  258. // Решить уравнение Ly=b
  259. template<typename T, typename T2=T>
  260. bool findY(std::vector<T>& y, SkylineStorageMatrix<T>& a, std::vector<T>& b)
  261. {
  262.     // dst = частное a и b.
  263.     // Если b = 0, вернуть false из текущей подпрограммы.
  264.  
  265.     #define _div(dst, a, b) { if (((b) > (T)0 ? (b) : -(b)) < (T)EPS) return false; dst = (a) / (b); }
  266.  
  267.     // Количество элементов в i'ой строке/столбце
  268.     #define elementsInLine(i) (a.ia[i + 1] - a.ia[i])
  269.  
  270.     for (unsigned int i = 0; i < a.di.size(); i++)
  271.     {
  272.         T2 sum = (T2)0;
  273.         unsigned int elementsInLineI = elementsInLine(i); // кол-во ненулевых элементов
  274.         // цикл по ним
  275.         for (unsigned int alIndex = a.ia[i], bIndex = i - elementsInLineI, counter = 0; counter < elementsInLineI; alIndex++, bIndex++, counter++)
  276.         {
  277.             sum += (T2)a.al[alIndex] * (T2)y[bIndex]; // суммирование
  278.         }
  279.  
  280.         _div(y[i], b[i] - sum, a.di[i]);         // Делим (b[i] - sum) на a.di[i] и сохраняем результат в y[i]
  281.     }
  282.  
  283.     #undef _div
  284.     #undef elementsInLine
  285.     return true;
  286. }
  287.  
  288. // Решить уравнение Ux=y
  289. template<typename T, typename T2=T>
  290. bool findX(std::vector<T>& x, SkylineStorageMatrix<T>& a, std::vector<T>& y)
  291. {
  292.     #define _div(dst, a, b) { if (((b) > (T)0 ? (b) : -(b)) < (T)EPS) return false; dst = (a) / (b); }
  293.  
  294.     // Количество элементов в i'ой строке/столбце
  295.     #define elementsInLine(i) (a.ia[i + 1] - a.ia[i])
  296.  
  297.     for (unsigned int i = a.di.size() - 1; true; i--)
  298.     {
  299.         T2 sum = (T2)0;
  300.         for (unsigned int j = i + 1; j < a.di.size(); j++)
  301.         {
  302.             unsigned int elementsInColJ = elementsInLine(j);
  303.             // Проверяем, есть ли ненулевые элементы в колонне j, которые влияют на текущую строку i
  304.             sum += (i < j - elementsInColJ) ? (T2)0 : (T2)a.au[a.ia[j] + (i - (j - elementsInColJ))] * x[j];
  305.         }
  306.         // Делим (y[i] - sum) на a.di[i] и сохраняем результат в x[i]
  307.         _div(x[i], y[i] - sum, a.di[i]);
  308.         if (i == 0) break; // Прерываем цикл, если достигли первой строки
  309.     }
  310.  
  311.     #undef _div
  312.     #undef elementsInLine
  313.     return true;
  314. }
  315.  
  316. // Решить уравнение Ax=B
  317. template<typename T, typename T2=T>
  318. bool solve(std::vector<T>& x, SkylineStorageMatrix<T>& a, std::vector<T>& b)
  319. {
  320.     std::vector<T> y(b.size()); // вектор "y" с размером "b"
  321.  
  322.     // Проверка на возможность LU-разложения
  323.     if (!LusqSkyline<T,T2>(a))
  324.     {
  325.         std::cerr << "Matrix is not LU(sq)-decomposeable" << std::endl;
  326.         return false;
  327.     }
  328.     // Решение промежуточной системы y = L * b
  329.     // методом проверки "L * y = b" и "U * x = y"
  330.     if (!findY<T,T2>(y, a, b) || !findX<T,T2>(x, a, y))
  331.     {
  332.         std::cerr << "System is inconsistent" << std::endl;
  333.         return false;
  334.     }
  335.  
  336.     return true;
  337. }
  338.  
  339. // Записать матрицу в профильном формате
  340. template<typename T>
  341. void writeSkyline(SkylineStorageMatrix<T>& from, std::ostream& to)
  342. {
  343.     to << from.di.size() << std::endl; // запись размера диагональных элементов
  344.     for (unsigned int i = 0; i < from.ia.size(); i++)
  345.     {
  346.         to << from.ia[i] << " ";
  347.     }
  348.     to << std::endl;
  349.  
  350.     for (unsigned int i = 0; i < from.al.size(); i++) // запись массива al
  351.     {
  352.         to << std::fixed << std::setprecision(14) << from.al[i] << " ";
  353.     }
  354.     to << std::endl;
  355.     for (unsigned int i = 0; i < from.au.size(); i++) // au
  356.     {
  357.         to << std::fixed << std::setprecision(14) << from.au[i] << " ";
  358.     }
  359.     to << std::endl;
  360.  
  361.     for (unsigned int i = 0; i < from.di.size(); i++) // di
  362.     {
  363.         to << std::fixed << std::setprecision(14) << from.di[i] << " ";
  364.     }
  365.     to << std::endl;
  366. }
  367.  
  368. // Записать вектор
  369. template<typename T>
  370. void writeVector(std::vector<T>& from, std::ostream& to)
  371. {
  372.     to << from.size() << std::endl;  // запись размера массива
  373.  
  374.     for (unsigned int i = 0; i < from.size(); i++)    
  375.     {
  376.         to << std::fixed << std::setprecision(14) << from[i] << std::endl;
  377.         // каждый элемент выводится в фиксированном формате с точностью 14 знаков
  378.     }
  379.     to << std::endl;
  380. }
  381.  
  382. // Провести серию тестов на число обусловленности
  383. void conditionNumberTestSeries(int tests)
  384. {
  385.     // создание таблицы для вывода
  386.     std::cout << "\\newline{\\tiny\\tt\\begin{tabular}{| l | p{3cm} | p{1cm} | p{3cm} | p{1cm} | p{3cm} | p{1cm} |}\n\\hline\n";
  387.     std::cout << "k & $x^k$ (float) & $x^* - x^k$ (float) & $x^k$ (double) & $x^* - x^k$ (double) & $x^k$ (mixed) & $x^* - x^k$ (mixed) \\\\ \\hline\n";
  388.  
  389.     for (int test = 0; test < tests; test++)
  390.     {
  391.         // чтение матрица и вектора float
  392.         std::fstream f_ifile("test6.txt");
  393.         struct SkylineStorageMatrix<float> f_a;
  394.         readSkyline(f_ifile, f_a);              // матрица
  395.         int n = f_a.di.size();
  396.         std::vector<float> f_b;
  397.         readVector(f_ifile, f_b);               // вектор
  398.         f_a.di[0] += (float)pow(10.0, -test);   // проверка на устойчивость
  399.         f_b[0] += (float)(pow(10.0, -test));
  400.         // в первый элемент диагонального вектора матрицы и вектора b добавляется небольшое значение
  401.         // зависимое от номера теста
  402.         std::vector<float> f_x(n);
  403.         bool ok1 = solve(f_x, f_a, f_b);
  404.  
  405.         // double
  406.         std::fstream d_ifile("test6.txt");
  407.         struct SkylineStorageMatrix<double> d_a;
  408.         readSkyline(d_ifile, d_a);
  409.         std::vector<double> d_b;
  410.         readVector(d_ifile, d_b);
  411.         d_a.di[0] += (double)pow(10.0, -test);
  412.         d_b[0] += (double)(pow(10.0, -test));
  413.         std::vector<double> d_x(n);
  414.         bool ok2 = solve(d_x, d_a, d_b);
  415.  
  416.         // mixed
  417.         std::fstream m_ifile("test6.txt");
  418.         struct SkylineStorageMatrix<float> m_a;
  419.         readSkyline(m_ifile, m_a);
  420.         std::vector<float> m_b;
  421.         readVector(m_ifile, m_b);
  422.         m_a.di[0] += (float)pow(10.0, -test);
  423.         m_b[0] += (float)(pow(10.0, -test));
  424.         std::vector<float> m_x(n);
  425.         bool ok3 = solve<float,double>(m_x, m_a, m_b);
  426.  
  427.         // std::scientific, std::fixed - добавляют точность при форматировании
  428.         //
  429.  
  430.         if (ok1 || ok2)
  431.         {
  432.             std::cout << test << " & ";
  433.             for (int i = 0; i < n; i++)
  434.             {
  435.                 std::cout<< std::fixed << std::setprecision(7) << f_x[i] << "\\newline";
  436.             }
  437.             std::cout << " & ";
  438.             for (int i = 0; i < n; i++)
  439.             {
  440.                 std::cout << std::scientific << std::setprecision(2) << fabs((i + 1) - f_x[i]) << "\\newline";
  441.             }
  442.             std::cout << " & ";
  443.             for (int i = 0; i < n; i++)
  444.             {
  445.                 std::cout << std::fixed << std::setprecision(14) << d_x[i] << "\\newline";
  446.             }
  447.             std::cout << " & ";
  448.             for (int i = 0; i < n; i++)
  449.             {
  450.                 std::cout << std::scientific << std::setprecision(2) << dabs((i + 1) - d_x[i]) << "\\newline";
  451.             }
  452.             std::cout << " & ";
  453.             for (int i = 0; i < n; i++)
  454.             {
  455.                 std::cout << std::fixed << std::setprecision(7) << m_x[i] << "\\newline";
  456.             }
  457.             std::cout << " & ";
  458.             for (int i = 0; i < n; i++)
  459.             {
  460.                 std::cout << std::scientific << std::setprecision(2) << fabs((i + 1) - m_x[i]) << "\\newline";
  461.             }
  462.             std::cout << " \\\\ \\hline \n";
  463.         }
  464.  
  465.         if (test != tests - 1)
  466.         {
  467.             std::cout << "\\end{tabular}\\newline\\newline\\newline\n";
  468.             std::cout << "\\begin{tabular}{| l | p{3cm} | p{1cm} | p{3cm} | p{1cm} | p{3cm} | p{1cm} |}\n\\hline\n";
  469.             std::cout << "k & $x^k$ (float) & $x^* - x^k$ (float) & $x^k$ (double) & $x^* - x^k$ (double) & $x^k$ (mixed) & $x^* - x^k$ (mixed) \\\\ \\hline\n";
  470.         }
  471.     }
  472.  
  473.     std::cout << "\\end{tabular}}\n";
  474. }
  475.  
  476.  
  477. // Решить систему Ax=B с плотной матрицей методом Гаусса с выбором ведущего элемента
  478. template<typename T>
  479. bool solveGauss(std::vector<std::vector<T>> A, std::vector<T>& x, std::vector<T> B)
  480. {
  481.     unsigned int n = A.size();
  482.     std::vector<std::vector<T>> t = A;
  483.  
  484.     for (unsigned int k = 0; k < n - 1; k++)
  485.     {
  486.         // Постолбцовый выбор главного элемента
  487.         int m = k;
  488.         for (int i = k + 1; i < n; i++)
  489.         {
  490.             if (abs(A[i][k]) > abs(A[m][k]))
  491.             {
  492.                 m = i;
  493.             }
  494.         }
  495.         if (abs(A[m][k]) < 1E-5)
  496.         {
  497.             return false; // Система не имеет уникального решения
  498.         }
  499.         for (int j = k; j < n; j++)
  500.         {
  501.             T tmp = A[k][j];
  502.             A[k][j] = A[m][j];
  503.             A[m][j] = tmp;
  504.         }
  505.         T tmp = B[k];
  506.         B[k] = B[m];
  507.         B[m] = tmp;
  508.         // Конец
  509.  
  510.         for (int i = k + 1; i < n; i++)
  511.         {
  512.             t[i][k] = A[i][k] / A[k][k];
  513.             B[i] = B[i] - t[i][k] * B[k];
  514.  
  515.             for (int j = k + 1; j < n; j++)
  516.             {
  517.                 A[i][j] -= t[i][k] * A[k][j];
  518.             }
  519.         }
  520.     }
  521.  
  522.     x[n - 1] = B[n - 1] / A[n - 1][n - 1];
  523.     for (int k = n - 2; k >= 0; k--)
  524.     {
  525.         T sum = 0.0;
  526.         for (int j = k + 1; j < n; j++)
  527.         {
  528.             sum += A[k][j] * x[j];
  529.         }
  530.  
  531.         x[k] = (B[k] - sum) / A[k][k];
  532.     }
  533. }
  534.  
  535. // Сравнить Гаусса и разложение тестами на числом обусловленности
  536. void compareGaussLusq(int tests)
  537. {
  538.     std::cout << "\\newline{\\tiny\\tt\\begin{tabular}{| l | p{3cm} | p{1cm} | p{3cm} | p{1cm} |}\n\\hline\n";
  539.     std::cout << "k & $x^k$ (LU(sq)) & $x^* - x^k$ (LU(sq)) & $x^k$ (Gauss) & $x^* - x^k$ (Gauss) \\\\ \\hline\n";
  540.  
  541.     for (int test = 0; test < tests; test++)
  542.     {
  543.         std::fstream d_ifile("test6.txt");
  544.         struct SkylineStorageMatrix<double> d_a;
  545.         readSkyline(d_ifile, d_a);
  546.         int n = d_a.di.size();
  547.         std::vector<double> d_b;
  548.         readVector(d_ifile, d_b);
  549.         d_a.di[0] += (double)pow(10.0, -test);
  550.         d_b[0] += (double)(pow(10.0, -test));
  551.         std::vector<double> d_x(n);
  552.         bool ok1 = solve(d_x, d_a, d_b);
  553.  
  554.         std::fstream g_ifile("test6.txt");
  555.         struct SkylineStorageMatrix<double> g_a;
  556.         readSkyline(g_ifile, g_a);
  557.         std::vector<double> g_b;
  558.         readVector(g_ifile, g_b);
  559.         g_a.di[0] += (double)pow(10.0, -test);
  560.         g_b[0] += (double)(pow(10.0, -test));
  561.         std::vector<std::vector<double>> A;
  562.         skylineToSquare(g_a, A);
  563.         std::vector<double> g_x(n);
  564.         bool ok2 = solveGauss(A, g_x, g_b);
  565.  
  566.         if (ok1 || ok2)
  567.         {
  568.             std::cout << test << " & ";
  569.             for (int i = 0; i < n; i++)
  570.             {
  571.                 std::cout<< std::fixed << std::setprecision(14) << d_x[i] << "\\newline";
  572.             }
  573.             std::cout << " & ";
  574.             for (int i = 0; i < n; i++)
  575.             {
  576.                 std::cout << std::scientific << std::setprecision(2) << dabs((i + 1) - d_x[i]) << "\\newline";
  577.             }
  578.             std::cout << " & ";
  579.             for (int i = 0; i < n; i++)
  580.             {
  581.                 std::cout << std::fixed << std::setprecision(14) << g_x[i] << "\\newline";
  582.             }
  583.             std::cout << " & ";
  584.             for (int i = 0; i < n; i++)
  585.             {
  586.                 std::cout << std::scientific << std::setprecision(2) << dabs((i + 1) - g_x[i]) << "\\newline";
  587.             }
  588.             std::cout << " \\\\ \\hline \n";
  589.         }
  590.  
  591.         if (test != tests - 1)
  592.         {
  593.             std::cout << "\\end{tabular}\\newline\\newline\\newline\n";
  594.             std::cout << "\\begin{tabular}{| l | p{3cm} | p{1cm} | p{3cm} | p{1cm} |}\n\\hline\n";
  595.             std::cout << "k & $x^k$ (LU(sq)) & $x^* - x^k$ (LU(sq)) & $x^k$ (Gauss) & $x^* - x^k$ (Gauss) \\\\ \\hline\n";
  596.         }
  597.     }
  598.  
  599.     std::cout << "\\end{tabular}}\n";
  600. }
  601.  
  602. // Сгенерировать матрицу Гильберта
  603. template<typename T>
  604. void generateHilbert(SkylineStorageMatrix<T>& dst, std::vector<T>& dstr, int n)
  605. {
  606.     // Создаем квадратную матрицу для удобства заполнения значениями
  607.     std::vector<std::vector<T>> square(n);
  608.     for (int i = 0; i < n; i++)
  609.     {
  610.         square[i].resize(n);    // Инициализируем каждую строку квадратной матрицы
  611.     }
  612.  
  613.     // Инициализация массива индексов начала строк для профильной матрицы
  614.     dst.ia.resize(n + 1);
  615.     dst.ia[0] = 0;
  616.     dst.ia[1] = 0;
  617.     for (int i = 2; i < n + 1; i++)
  618.     {
  619.         dst.ia[i] = dst.ia[i - 1] + (i - 1);   // Количество ненулевых элементов в строке i равно i - 1
  620.     }
  621.  
  622.     int ii, jj;     // текущая строка, столбец
  623.     T sumij = (T)0;
  624.  
  625.     // Инициализируем массив для хранения ненулевых элементов в профильном формате
  626.     dst.al.resize(dst.ia[n]);
  627.     ii = 1, jj = 0; // 2 строка, 1 столбец
  628.     for (int i = 0; i < dst.ia[n]; i++)
  629.     {
  630.         // Заполняем элемент матрицы Гильберта по формуле H_{ij} = 1 / (i + j + 1)
  631.         dst.al[i] = (T)((T)1 / (T)(ii + jj + 1));
  632.         // Сохраняем элемент в квадратную матрицу для удобства
  633.         sumij += dst.al[i];
  634.  
  635.         square[ii][jj] = dst.al[i];         // Сохраняем элемент в квадратную матрицу для удобства
  636.         if (++jj == ii)                     // Переход к следующему элементу в строке
  637.         {
  638.             // Если достигли конца текущей строки, переходим на следующую
  639.             // Увеличиваем номер строки и сбрасываем номер столбца
  640.             ii++, jj = 0;
  641.         }
  642.     }
  643.  
  644.     // Инициализация массива для хранения
  645.     // ненулевых элементов в профильном формате
  646.     dst.au.resize(dst.ia[n]); // резервируем память
  647.     ii = 1, jj = 0;           // 1 столбец 2 строка
  648.     for (int i = 0; i < dst.ia[n]; i++)
  649.     {
  650.         dst.au[i] = (T)((T)1 / (T)(ii + jj + 1));
  651.         sumij += dst.au[i]; /// куда ведет переменная(???)
  652.  
  653.         square[jj][ii] = dst.al[i];
  654.         if (++jj == ii)
  655.         {
  656.             ii++, jj = 0;
  657.         }
  658.     }
  659.  
  660.     dst.di.resize(n);
  661.     for (int i = 0; i < n; i++)
  662.     {
  663.         dst.di[i] = (T)((T)1 / (T)(i + i + 1));;
  664.         square[i][i] = dst.di[i]; // заполняем диагональные по формуле Гильберта
  665.     }
  666.  
  667.     // Вектор
  668.     dstr.resize(n);
  669.     for (int i = 0; i < n; i++)
  670.     {
  671.         dstr[i] = (T)0;
  672.         for (int j = 0; j < n; j++)
  673.         {
  674.             // Вычисляем элемент dstr[i] как сумму произведений элементов матрицы square и индексов
  675.             dstr[i] += square[i][j] * (T)(j + 1);
  676.         }
  677.     }
  678.  
  679.     // printMatrix(square); // отладка
  680.     std::ostringstream os; os << n;
  681.     std::fstream out("hilbert" + std::string(os.str()) + ".txt", std::ios::out);
  682.     writeSkyline(dst, out);  // Записываем профильную матрицу в файл
  683. }
  684.  
  685. // Провести серию тестов с матрицами Гильберта размерности от n1 до n2
  686. void hilbertTestSeries(int n1, int n2)
  687. {
  688.     std::cout << "\\newline{\\tiny\\tt\\begin{tabular}{| l | p{3cm} | p{3cm} | p{3cm} | p{3.1cm} |}\n\\hline\n";
  689.     std::cout << "k & $x^k$ (float) & $x^* - x^k$ (float) & $x^k$ (double) & $x^* - x^k$ (double) \\\\ \\hline\n";
  690.  
  691.     for (int n = n1; n <= n2; n++)
  692.     {
  693.         struct SkylineStorageMatrix<float> f_a;
  694.         std::vector<float> f_b;
  695.         generateHilbert(f_a, f_b, n);
  696.         std::vector<float> f_x(n);
  697.         bool ok1 = solve(f_x, f_a, f_b);
  698.  
  699.         struct SkylineStorageMatrix<double> d_a;
  700.         std::vector<double> d_b;
  701.         generateHilbert(d_a, d_b, n);
  702.         std::vector<double> d_x(n);
  703.         bool ok2 = solve(d_x, d_a, d_b);
  704.  
  705.         std::cout << n << " & ";
  706.         for (int i = 0; i < n; i++)
  707.         {
  708.             std::cout << std::fixed << std::setprecision(7) << (ok1 ? f_x[i] : 0.0) << "\\newline";
  709.         }
  710.         std::cout << " & ";
  711.         for (int i = 0; i < n; i++)
  712.         {
  713.             std::cout << std::scientific << std::setprecision(2) << fabs(ok1 ? ((i + 1) - f_x[i]) : 0.0) << "\\newline";
  714.         }
  715.         std::cout << " & ";
  716.         for (int i = 0; i < n; i++)
  717.         {
  718.             std::cout << std::fixed << std::setprecision(14) << (ok2 ? d_x[i] : 0.0) << "\\newline";
  719.         }
  720.         std::cout << " & ";
  721.         for (int i = 0; i < n; i++)
  722.         {
  723.             std::cout << std::scientific << std::setprecision(2) << dabs(ok2 ? ((i + 1) - d_x[i]) : 0.0) << "\\newline";
  724.         }
  725.         std::cout << " \\\\ \\hline \n";
  726.  
  727.         if (n != n2)
  728.         {
  729.             std::cout << "\\end{tabular}\\newline\\newline\\newline\n";
  730.             std::cout << "\\begin{tabular}{| l | p{3cm} | p{3cm} | p{3cm} | p{3.1cm} |}\n\\hline\n";
  731.             std::cout << "k & $x^k$ (float) & $x^* - x^k$ (float) & $x^k$ (double) & $x^* - x^k$ (double) \\\\ \\hline\n";
  732.         }
  733.     }
  734.  
  735.     std::cout << "\\end{tabular}}\n";
  736. }
  737.  
  738. int main(int argc, char** argv)
  739. {
  740.      // Проверяем, что передано
  741.      // 4 аргумента и первый аргумент - "solve-double"
  742.     if (argc == 4 && std::string(argv[1]) == "solve-double")
  743.     {
  744.         std::fstream ifile(argv[2], std::ios::in); // Открываем входной файл для чтения
  745.         struct SkylineStorageMatrix<double> a;// Создаем объект для хранения матрицы в профильном формате
  746.         readSkyline(ifile, a);  // Читаем профильную матрицу из файла
  747.         std::vector<double> b; // Вектор для хранения правой части системы
  748.         readVector(ifile, b);  // Читаем вектор из файла
  749.  
  750.         std::fstream ofile(argv[3], std::ios::out); // Открываем выходной файл для записи
  751.         std::vector<double> x(b.size()); // Вектор для хранения решения
  752.         solve(x, a, b);  // Решаем систему уравнений
  753.         writeVector(x, ofile); // Записываем решение в выходной файл
  754.     }
  755.     else if (argc == 4 && std::string(argv[1]) == "solve-float")
  756.     {
  757.         std::fstream ifile(argv[2], std::ios::in);
  758.         struct SkylineStorageMatrix<float> a;
  759.         readSkyline(ifile, a);
  760.         std::vector<float> b;
  761.         readVector(ifile, b);
  762.  
  763.         std::fstream ofile(argv[3], std::ios::out);
  764.         std::vector<float> x(b.size());
  765.         solve(x, a, b);
  766.         writeVector(x, ofile);
  767.     }
  768.     else if (argc == 4 && std::string(argv[1]) == "solve-double-square")
  769.     {
  770.         std::fstream ifile(argv[2], std::ios::in);
  771.         struct SkylineStorageMatrix<double> a;
  772.         readSkyline(ifile, a);
  773.         std::vector<double> b;
  774.         readVector(ifile, b);
  775.  
  776.         std::vector<std::vector<double>> A;
  777.         skylineToSquare(a, A);
  778.  
  779.         std::fstream ofile(argv[3], std::ios::out);
  780.         std::vector<double> x(b.size());
  781.         solveGauss(A, x, b); // Решаем систему уравнений методом Гаусса
  782.         writeVector(x, ofile);
  783.     }
  784.     else if (argc == 4 && std::string(argv[1]) == "hilbert")
  785.     {
  786.         std::istringstream os1(argv[2]); int from; os1 >> from;
  787.         std::istringstream os2(argv[3]); int to; os2 >> to;
  788.         hilbertTestSeries(from, to); // Запускаем тестирование матриц Гильберта
  789.     }
  790.     else if (argc == 3 && std::string(argv[1]) == "condition")
  791.     {
  792.         std::istringstream os(argv[2]); int n; os >> n;
  793.         conditionNumberTestSeries(18); // Запускаем тестирование числа обусловленности
  794.     }
  795.     else if (argc == 3 && std::string(argv[1]) == "competition")
  796.     {
  797.         std::istringstream os(argv[2]); int n; os >> n;
  798.         compareGaussLusq(18); // Сравниваем методы Гаусса и LU-разложения
  799.     }
  800.     else
  801.     {
  802.         // Выводим сообщение о правильном использовании программы
  803.         std::cerr << "Usage: " << argv[0] << " solve-double test.txt output.txt" << std::endl
  804.                   << "       " << argv[0] << " solve-float test.txt output.txt" << std::endl
  805.                   << "       " << argv[0] << " solve-double-square test.txt output.txt" << std::endl
  806.                   << "       " << argv[0] << " solve-float-square test.txt output.txt" << std::endl
  807.                   << "       " << argv[0] << " hilbert from to" << std::endl
  808.                   << "       " << argv[0] << " condition n" << std::endl
  809.                   << "       " << argv[0] << " competition n" << std::endl;
  810.     }
  811.  
  812.     return 0;
  813. }
  814.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement