Разложение LU в c ++ не работает на больших матрицах

0

UPDATE: вот решение, я добавил скаляр в каждую строку, чтобы подтолкнуть нижний поток, переполнение под контролем. Спасибо за всю помощь, ребята.

Я работаю над разложением LU в c++, который, надеюсь, однажды разложит и разрешит большую разреженную матрицу. Я нашел код и модифицировал его для собственного использования, но он не будет работать на больших матрицах. Он работает на матрицах размером до 5 на 5. Мне нужно, чтобы он работал для матриц размером 100 на 100 и более. Я проверил свои решения в mat-lab, и мой код дает совершенно неправильные результаты. Я чувствую, что проблема связана с разделом в моем коде, и если да, то любые предложения относительно того, как решить эту проблему, будут очень благодарны, и любая помощь будет принята с большой благодарностью.

Вот мой код.

ОБНОВЛЕНО:

 #include <algorithm>
 // **
 * END ***
 /*
 * LUDecomp.cpp
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 #include <iostream>
 #include <fstream>
 #include <string.h>
 #include <iomanip>

 #include "LUDecomp.h"

 using namespace std;

 LUDecomp::LUDecomp()
 {
 }

 void LUDecomp::h_pivot_decomp(int MAT1, double a[], int p[], int q[])
 {
int i = 0, j = 0, k = 0;
int n = MAT1;
int pi = 0, pj = 0, tmp = 0;
double max = 0.0;
double ftmp = 0.0;
//Stores the scaling of each row or column.
double* vv = new double[MAT1 + 5];

//Loop over rows toget the implicit scaling information.
max = 0.0;
for (i = 0; i < n; i++)
{
    for (j = 0; j < n; j++)
    {

        if ((ftmp = fabs(a(i,j))) > max)
        {
            max=ftmp;
        }
    }
    //No nonzero largest element.
                if (max == 0.0)
                {
                    throw("Singular matrix in LUdcmp");
                }
                //Save the scaling.
                vv[i]=1.0/max;

            }

        // The k element determines which pivot element you are in thereby
        // determining the submatrix starting at the upper left corner of the matrix.
for (k = 0; k < n; k++)
{

    // pi: stores row needing to be swapped.
    // pj: stores column needing to be swapped.
    // max: makes a zero element in the matrix into a very tiny number.
    pi = -1, pj = -1, max = TINY;

    //find pivot in submatrix a(k:n,k:n) by finding the absolute value of the biggest element.
    for (i = k; i < n; i++)
    {
        for (j = k; j < n; j++)
        {
            //j = k;
            ftmp = vv[i] * fabs(a(i,j));
            // Decides if current max is bigger than current element.
                    if (ftmp>max)
                    {
                        max = ftmp;
                        // Index of row being swapped.
                        pi=i;
                        // Index of column being swapped.
                        pj=j;
                    }
                }
            }

    {
        // Stores the permutation of row swaps.
        tmp = p[k];
        p[k] = p[pi];
        p[pi] = tmp;
    }

    //Swaps the scalling factor if needed.
    if (k != pi)
    {
        vv[pi] = vv[k];
        cout << "Scaling factor: " << vv[pi] << endl;
    }

    // Swaps the indicated rows to move the max pivot
    // element of the submatrix k into place.
    for (j = 0; j < n; j++)
    {
        // The k and pi index stays the same so the row
        // number stays the same, the j changes to iterate threw the row.
        ftmp = a(k,j);
        a(k,j)=a(pi,j);
        a(pi,j)=ftmp;
        //cout << a(k,j) << " , " << a(pi,j) << endl;
            }

    {
        // Stores the permutation of column swaps.
        tmp = q[k];
        q[k] = q[pj];
        q[pj] = tmp;
        //cout << q[k] << " , " << q[pj] << endl;
    }

    // Swaps the indicated columns to move the max pivot
    // element of the submatrix k into place.
    for (i = 0; i < n; i++)
    {
        // The k and pj index stays the same so the column
        // number stays the same, the i changes to iterate threw the column.
        ftmp = a(i,k);
        a(i,k)=a(i,pj);
        a(i,pj)=ftmp;
        //cout << a(i,k) << " , " << a(i,pj) << endl;
            }
        // END PIVOT
    cout << fixed << showpoint;
    cout << setprecision(20);
    // Check pivot size and decompose
    if ((fabs(a(k,k))>TINY))
    {
        for (i=k+1;i<n;i++)
        {
            // Column normalisation, Does first element under pivot k row i.

            ftmp=a(i,k)/=a(k,k);

            cout << "k,k " <<a(k,k) << " , " << endl;
            // Does the rest of row i.
            for (j=k+1;j<n;j++)
            {
                //a(ik)*a(kj) subtracted from lower right submatrix elements
                a(i,j)-=(ftmp*a(k,j));
                //cout <<"i,j "<< a(i,j) << endl;
            }
        }
    }

}
    //END DECOMPOSE
for (i = 0; i < n; i++)
{
    for (j = 0; j < n; j++)
    {

        cout << a(i,j)<<" ";
    }
    cout << endl;
}
 }

 void LUDecomp::h_solve(int MAT1, double a[], double x[], int p[], int q[])
 {
// Forward substitution; see  Golub, Van Loan 96
// And see http://www.cs.rutgers.edu/~richter/cs510/completePivoting.pdf
int i = 0, ii = 0, j = 0;
double ftmp = 0.0;
double* xtmp = new double[MAT1 + 5];

cout << fixed << showpoint;
cout << setprecision(4);

// Swap rows
// Put be vector back like it should be by using the permutations from the row swapping.
for (i = 0; i < MAT1; i++)
{
    xtmp[i] = x[p[i]]; //value that should be here
    //cout << xtmp[i] << endl;
}

// Ly=b
for (i = 0; i < MAT1; i++)
{
    ftmp = xtmp[i];
    if (ii != 0)
        for (j = ii - 1; j < i; j++)
            ftmp -= a(i,j)*xtmp[j];

            else if (ftmp!=0.0)
            ii=i+1;

    xtmp[i] = ftmp;
    //cout << xtmp[i] << endl;
}

// Backward substitution
// Partially taken from Sourcebook on Parallel Computing p577
// Solves Ux=y
cout << "xtmp " << xtmp[MAT1 - 1] << " a " << a(MAT1-1,MAT1-1)<< endl;
xtmp[MAT1 - 1] /= a(MAT1-1,MAT1-1);
//cout << xtmp[MAT1 - 1] << endl;
for (i = MAT1 - 2; i >= 0; i--)
{
    ftmp = xtmp[i];
    //cout << "ftmp " << ftmp << endl;
    for (j = i + 1; j < MAT1; j++)
    {
        ftmp -= a(i,j)*xtmp[j];
        //cout << "ftmp in "<<ftmp << endl;
    }

    xtmp[i] = (ftmp) / a(i,i);

}

    // Last bit
    // Swap columns
    // Takes the final answer and puts it back into its proper order by
    // using the permutations from the column swapping.
for (i = 0; i < MAT1; i++)
{
    x[q[i]] = xtmp[i];
}

delete xtmp;
 }

 // Method to get output from the LU Decomposition.
 void LUDecomp::output(unsigned int MAT1, double a[], double b[])
 {

// Pivot array for the permutation vectors.
int* p_pivot = new int[MAT1 + 5];
int* q_pivot = new int[MAT1 + 5];

// Sets the elements in the permutation vectors up to receive permutations.
// p_pivot is for row permutations and is initialized to {0,1,...,r};
// q_pivot is for column permutations and is initialized to {0,1,...,r};
for (unsigned int i = 0; i < MAT1; i++)
{
    p_pivot[i] = i;
    q_pivot[i] = i;
}

// Call to decomposition method passing (size,matrix to be decomposed, not used,   not used).
h_pivot_decomp(MAT1, a, p_pivot, q_pivot);

// Call to solve passing (size, matrix in LU form, b vector, not used, not used).
h_solve(MAT1, a, b, p_pivot, q_pivot);

// Have solution.
// Used for file output.
ofstream outFile;
// Allow for appenending to a file already created.
outFile.open("outSolMatrix.txt");

// Sets the precision of the output to the file.
outFile << fixed << showpoint;
outFile << setprecision(4);

// Output results to file answer is {0,1,...,n}.
for (unsigned int i = 0; i < MAT1; i++)
{
    outFile << i << " " << b[i] << endl;
}

outFile << "End" << endl;

delete p_pivot;
delete q_pivot;

outFile.close();
 }

Файл h здесь, если вам нужно его увидеть.

#ifndef LUDECOMP_H_
#define LUDECOMP_H_

class LUDecomp {

public:

#define a(i,j) a[(i)*MAT1+(j)]

const static double TINY = 1e-20;

LUDecomp();

void h_pivot_decomp(int MAT1, float *a, int *p, int *q);
void h_solve(int MAT1, float *a, float *x, int *p, int *q);
void output(unsigned int MAT1, float *a, float *b);

private:

};

#endif /* LUDECOMP_H_ */

Еще раз спасибо, дайте мне знать, если вы, ребята, должны увидеть что-нибудь еще.

Теги:
math
matrix

1 ответ

2

Попробуйте заменить float на double. Float не очень хороший тип для сложных вычислений, потому что он очень маленький (всего 4 байта), поэтому не точный (всего 7-8 цифр). Поэтому лучше использовать double (8 байт, 15-16 цифр). Но если вам нужны более точные вычисления, вам нужно использовать другие структуры данных для значений (например, в Matlab, Maple и других системах). См. Арифметику с произвольной точностью.

  • 2
    Ну да, до определенного момента. Переключение с float на double не (надежно) устраняет основную числовую нестабильность, оно просто скрывает их лучше. Если нестабильность является причиной проблемы OP, совет в комментарии @ ligtalchemist гораздо лучше.
  • 0
    Я сделал это в другой версии кода, это только минимизировало проблему, когда матрица очень большая, решения становятся совершенно неправильными. Благодарю.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню