// LLT разложение, матрица в профильном формате.
/*
* Структура программы:
* Ввод матрицы и вектора F
* Разложение матрицы на LLT составляющие
* Решение системы Ly = F (прямой ход)
* Решение системы LTx = y (обратный ход)
*/
#include
#include
#include
#include
#include
typedef float real;
typedef float real_acc;
using namespace std;
const string file1("matrix.txt"); // Имя файла, содержащего матрицу в профильном формате.
const string file2("vector.txt"); // Вектор - результат умножения матрицы на искомый вектор.
const string file3("result.txt"); // Искомый вектор - решение СЛАУ.
const string file4("subs.txt"); // Погрешность вычислений.
size_t N = 0; // Размерность матрицы
vector ia;
vector di;
vector al;
vector F;
vector x;
vector y; // Промежуточный вектор для прямого хода.
void input(string file1, string file2);
void LLT_dec();
void straight_stroke();
void reverse_stroke();
void cond_test_gen(size_t k, string file3, string file4);
void gilbert_test_gen(size_t k, string file3, string file4);
void Gauss_test_gen(size_t k, string file3, string file4);
void main()
{
size_t k = 5;
//input(file1, file2);
//cond_test_gen(k, file3, file4);
//gilbert_test_gen(k, file3, file4);
Gauss_test_gen(k, file3, file4);
N = 2;
int SUMMA = 0;
for (size_t k = 0; k < N; k++)
{
for (size_t i = 0; i < N + 1; i++)
SUMMA++;
for (size_t i = k + 1; i < N; i++)
{
SUMMA++;
for (size_t j = 0; j < N + 1; j++)
SUMMA += 2;
}
}
cout << SUMMA;
for (int k = N - 1; k > -1; k--)
{
for (int i = N; i > -1; i--)
SUMMA++;
for (int i = k - 1; i > -1; i--)
{
SUMMA++;
for (int j = N; j > -1; j--)
SUMMA += 2;
}
}
}
/*
* 1. Преобразование особых матрицы и вектора F
* к нужному виду.
* 2. Решение СЛАУ.
* 3. Запись результата и погрешности относительно
* точного решения.
*/
void cond_test_gen(size_t k, string file3, string file4)
{
di[0] += 1.0 / pow(10, k);
F[0] += 1.0 / pow(10, k);
LLT_dec();
straight_stroke();
reverse_stroke();
// Вывод искомого вектора.
size_t prec = 0;
k < 7 ? prec = 7 : prec = 14;
ofstream fout(file3);
for (size_t i = 0; i < N; i++)
fout << scientific << setprecision(prec) << x[i] << endl;
fout.close();
// Вывод погрешности относительно точного вектора.
ofstream fout2(file4);
vector x_acc = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
for (size_t i = 0; i < 10; i++)
fout2 << scientific << setprecision(2) << abs(x_acc[i] - x[i]) << endl;
fout2.close();
}
/*
* 1. Создание матрицы Гильберта k-той размерности и
* вектора F умножением на x(1, ..., N).
* 2. Решение СЛАУ.
* 3. Запись результата и погрешности относительно
* точного решения.
*/
void gilbert_test_gen(size_t k, string file3, string file4)
{
N = k;
ia.resize(N + 1);
ia[0] = 0;
for (size_t i = 0; i < N; i++)
ia[i + 1] = ia[i] + i;
al.resize(ia[N]);
di.resize(N);
for (size_t i = 0; i < N; i++)
{
size_t i0 = ia[i]; // Индекс начального элемента i-той строки в массиве al.
size_t i1 = ia[i + 1]; // Индекс начального элемента i + 1 стоки.
size_t j = i - (i1 - i0); // Номер столбца первого элемента в строке.
for (size_t ij = i0; ij < i1; ij++, j++)
al[ij] = 1.0 / (i + j + 1);
di[i] = 1.0 / (2 * i + 1);
}
F.resize(N);
for (size_t i = 0; i < N; i++)
{
size_t ind = i + ia[i] - ia[i + 1];
for (size_t j = ia[i]; j < ia[i + 1]; j++)
{
F[i] += al[j] * (ind + 1);
F[ind] += al[j] * (i + 1);
ind++;
}
F[i] += di[i] * (i + 1);
}
y.resize(N);
x.resize(N);
LLT_dec();
straight_stroke();
reverse_stroke();
// Вывод искомого вектора.
size_t prec = 0;
k < 7 ? prec = 7 : prec = 14;
ofstream fout(file3);
fout << scientific << setprecision(14);
for (size_t i = 0; i < N; i++)
fout << x[i] << endl;
fout.close();
// Вывод погрешности относительно точного вектора.
ofstream fout2(file4);
vector x_acc(N);
for (size_t i = 0; i < N; i++)
x_acc[i] = i + 1;
fout2 << scientific << setprecision(2);
for (size_t i = 0; i < N; i++)
fout2 << abs(x_acc[i] - x[i]) << endl;
fout2.close();
}
void input(string file1, string file2)
{
// Переделать в сишные сканфс
// для контроля количества вводимых знаков.
ifstream fin(file1);
ifstream fin2(file2);
fin >> N;
ia.resize(N + 1);
for (size_t i = 0; i < N + 1; i++)
{
fin >> ia[i];
ia[i]--;
}
di.resize(N);
for (size_t i = 0; i < N; i++)
fin >> di[i];
al.resize(ia[N]);
for (size_t i = 0; i < ia[N]; i++)
fin >> al[i];
fin.close();
F.resize(N);
for (size_t i = 0; i < N; i++)
fin2 >> F[i];
fin2.close();
y.resize(N);
x.resize(N);
}
// LLT - разложение.
// Заменяет матрицу в массивах di и al нижнетреугольной L
void LLT_dec()
{
for (size_t i = 0; i < N; i++)
{
real_acc sumdi = 0.0;
size_t i0 = ia[i]; // Индекс начального элемента i-той строки в массиве al.
size_t i1 = ia[i + 1]; // Индекс начального элемента i + 1 стоки.
size_t j = i - (i1 - i0); // Номер столбца первого элемента в строке.
for (size_t ij = i0; ij < i1; ij++, j++)
{
real_acc suml = 0.0;
size_t j0 = ia[j]; // Индекс начального элемента j-той строки в массиве al.
size_t j1 = ia[j + 1]; // Индекс начального элемента j + 1 стоки.
size_t ik = i0;
size_t jk = j0;
size_t ci = ij - i0; // Количество элементов i-той строки.
size_t cj = j1 - j0; // Количество элементов j-той строки.
// Сдвиг индексов начальных элементов строк
// к первому существующему элементу наименьшей строки.
ci > cj ? ik += ci - cj : jk += cj - ci;
// Суммируем произведения элементов двух строк, стоящих до искомого.
for (; ik < ij; ik++, jk++)
suml += al[ik] * al[jk];
al[ij] = (al[ij] - suml) / di[j];
sumdi += al[ij] * al[ij];
}
di[i] = sqrt(di[i] - sumdi);
}
}
// Прямой ход. (Ly = F)
// Заполнение вектора y.
void straight_stroke()
{
for (size_t i = 0; i < N; i++)
{
size_t in = ia[i + 1];
size_t in_prev = ia[i];
size_t j = i - (in - in_prev);
real_acc sum = 0.0;
for (size_t k = in_prev; k < in; k++, j++)
sum += al[k] * y[j];
y[i] = (F[i] - sum) / di[i];
}
}
// Обратный ход. (LTx = y)
// Заполнение искомого вектора.
void reverse_stroke()
{
vector temp(N);
fill(temp.begin(), temp.end(), 0.0);
for (size_t i = N; i >= 1; i--)
{
size_t in = ia[i];
size_t in_prev = ia[i - 1];
x[i - 1] = (y[i - 1] - temp[i - 1]) / di[i - 1];
size_t j = i - 2;
for (size_t k = in; k > in_prev; k--, j--)
temp[j] += al[k - 1] * x[i - 1];
}
}
void Gauss_test_gen(size_t p, string file3, string file4)
{
vector> Matrix_Clone =
{
{ 8.0, 0.0, -3.0, 0.0, 0.0, 0.0, -1.0, -4.0, 0.0, 0.0, -40.0 },
{ 0.0, 5.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -2.0, -2.0, -32.0 },
{ -3.0, 0.0, 7.0, 0.0, -1.0, 0.0, -3.0, 0.0, 0.0, 0.0, -8.0 },
{ 0.0, -1.0, 0.0, 8.0, 0.0, -2.0, 0.0, 0.0, -1.0, -4.0, -31.0 },
{ 0.0, 0.0, -1.0, 0.0, 4.0, 0.0, 0.0, -3.0, 0.0, 0.0, -7.0 },
{ 0.0, 0.0, 0.0, -2.0, 0.0, 6.0, -3.0, 0.0, -1.0, 0.0, -2.0 },
{ -1.0, 0.0, -3.0, 0.0, 0.0, -3.0, 9.0, 0.0, 0.0, -2.0, 15.0 },
{ -4.0, 0.0, 0.0, 0.0, -3.0, 0.0, 0.0, 11.0, -4.0, 0.0, 33.0 },
{ 0.0, -2.0, 0.0, -1.0, 0.0, -1.0, 0.0, -4.0, 11.0, -3.0, 23.0 },
{ 0.0, -2.0, 0.0, -4.0, 0.0, 0.0, -2.0, 0.0, -3.0, 11.0, 49.0 }
};
N = Matrix_Clone.size();
Matrix_Clone[0][0] += 1.0 / pow(10, p);
Matrix_Clone[0][N] += 1.0 / pow(10, p);
vector> Matrix(N, vector (N + 1));
for (size_t i = 0; i < N; i++)
for (size_t j = 0; j < N + 1; j++)
Matrix[i][j] = Matrix_Clone[i][j];
// Прямой ход (Зануление нижнего левого угла)
for (size_t k = 0; k < N; k++) // k-номер строки.
{
for (size_t i = 0; i < N + 1; i++) // i-номер столбца.
Matrix_Clone[k][i] /= Matrix[k][k]; // Деление k-строки на первый член !=0 для преобразования его в единицу.
for (size_t i = k + 1; i < N; i++) // i-номер следующей строки после k.
{
real K = Matrix_Clone[i][k] / Matrix_Clone[k][k]; // Коэффициент.
for (size_t j = 0; j < N + 1; j++) // j-номер столбца следующей строки после k.
Matrix_Clone[i][j] -= Matrix_Clone[k][j] * K; // Зануление элементов матрицы ниже первого члена, преобразованного в единицу
}
for (size_t i = 0; i < N; i++) // Обновление, внесение изменений в начальную матрицу
for (size_t j = 0; j < N + 1; j++)
Matrix[i][j] = Matrix_Clone[i][j];
}
// Обратный ход (Зануление верхнего правого угла)
for (int k = N - 1; k > -1; k--) // k-номер строки
{
for (int i = N; i > -1; i--) // i-номер столбца
Matrix_Clone[k][i] /= Matrix[k][k];
for (int i = k - 1; i > -1; i--) //i-номер следующей строки после k
{
real K = Matrix_Clone[i][k] / Matrix_Clone[k][k];
for (int j = N; j > -1; j--) //j-номер столбца следующей строки после k
Matrix_Clone[i][j] -= Matrix_Clone[k][j] * K;
}
}
// Отделяем от общей матрицы ответы
vector x(N);
for (size_t i = 0; i < N; i++)
x[i] = Matrix_Clone[i][N];
// Вывод искомого вектора.
size_t prec = 0;
p < 7 ? prec = 7 : prec = 14;
ofstream fout(file3);
for (size_t i = 0; i < N; i++)
fout << scientific << setprecision(prec) << x[i] << endl;
fout.close();
// Вывод погрешности относительно точного вектора.
ofstream fout2(file4);
vector x_acc = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };
for (size_t i = 0; i < 10; i++)
fout2 << scientific << setprecision(2) << abs(x_acc[i] - x[i]) << endl;
fout2.close();
}