2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Почему то не могу считать матрицу
Сообщение22.07.2011, 12:48 


21/07/11
105
Есть матрица порядка 3638. Мне нужно найти обратную к ней. ( В последствии порядок матрицы будет около 100 000)
Есть код, вот только он не совсем рабочий. На маленьких матрицах порядка 3-4 он работает отлично, а вот на матрице порядка 3638 - не работает. В качестве результата выдает исходную матрицу.
Помогите найти косяк. И по возможности сделать код "по-шустрее"
Вот код на С++
Код:
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sstream>
#include <vector>
#include <string>
#include <ctime>
#include <cmath>
#include <math.h>
#include <conio.h>

using namespace std;

template <typename T> void FreeMem(T **matr, int n);
template <typename T> void PrintMtx(T **matr, int n);
template <typename T> void SetMtx(T **matr, int n);
template <typename T> void TransponMtx(T **matr, T **tMatr, int n);
void Get_matr(double **matr, int n, double **temp_matr, int indRow, int indCol);
double Det(double **matr, int n);

void main()
{
    srand((unsigned)time(NULL));
    setlocale(0, "");
    int n;
        double det;
    cout << "Введите размер матрицы: ";
    cin >> n;
    double **matr = new double * [n];
    double **obr_matr = new double * [n];
    for(int i = 0; i < n; i++)
                {
            matr[i] = new double[n];
            obr_matr[i] = new double[n];
        }
       
        SetMtx(matr, n);
        det = Det(matr, n);
        if(det != 0 ){
                for(int i = 0; i < n; i++){
                        for(int j = 0; j < n; j++){
                                int m = n - 1;
                                double **temp_matr = new double * [m];
                                for(int k = 0; k < m; k++)
                                        temp_matr[k] = new double[m];
                                Get_matr(matr, n, temp_matr, i, j);
                                obr_matr[j][i] = pow(-1.0, i + j + 2) * Det(temp_matr, m) / det;
                                FreeMem(temp_matr, m);
                        }
                }       
        }
        else
  cout << "Т.к. определитель матрицы = 0,\nто матрица вырожденная и обратной не имеет!!!" << endl;
        //Печать матрицы
        PrintMtx(obr_matr, n);
                // Освобождение памяти
        FreeMem(matr, n);
        FreeMem(obr_matr, n);
}
//Функция освобождения памяти
template <typename T> void FreeMem(T **matr, int n)
{
        for(int i = 0; i < n; i++)
                delete [] matr[i];
        delete [] matr;
}

//функция заполнения матрицы
template <typename T> void SetMtx(T **matr, int n)
{
        ifstream ifs1("1.txt");
        for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                                {
                                        ifs1 >> matr[i][j];
                                }
}

//функция печати матрицы
template <typename T> void PrintMtx(T **matr, int n)
{
        ofstream ofs4("2.txt");
        for (int i = 0; i < n; i++){
                for (int j = 0; j < n; j++)
                                        ofs4 << matr[i][j] << " ";
                                ofs4 << endl;
                } 
}

//функция вычеркивания строки и столбца
void Get_matr(double **matr, int n, double **temp_matr, int indRow, int indCol)       
{
        int ki = 0;
        for (int i = 0; i < n; i++){
                if(i != indRow){
                        for (int j = 0, kj = 0; j < n; j++){
                                if (j != indCol){
                                        temp_matr[ki][kj] = matr[i][j];
                                        kj++;
                                }
                        }
                        ki++;           
                }
        }
}

//функция вычисления определителя матрицы
double Det(double **matr, int n)     
{
        double temp = 0;   //временная переменная для хранения определителя
        int k = 1;              //степень
        if(n < 1){
                cout<<"Неверный размер матрицы!!!" << endl;
        return 0;
    }
        else if (n == 1)
                temp = matr[0][0];
        else if (n == 2)
                temp = matr[0][0] * matr[1][1] - matr[1][0] * matr[0][1];
        else{
                for(int i = 0; i < n; i++){
                        int m = n - 1;
                        double **temp_matr = new double * [m];
                        for(int j = 0; j < m; j++)
                                temp_matr[j] = new double [m];
                        Get_matr(matr, n, temp_matr, 0, i);
                        temp = temp + k * matr[0][i] * Det(temp_matr, m);
                        k = -k;
                        FreeMem(temp_matr, m);
                }
        }
        return temp;

Сами матрицы находятся в текстовых файлах. Прикрепил и их:
1.txt - матрица порядка 4 (пробная)
2.txt - сюда записывается результат работы программы
3.txt - матрица порядка 3638
http://www.fayloobmennik.net/817691

 !  PAV:
Замечание за дублирование темы!

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 13:48 
Заслуженный участник


11/05/08
32166
Вам же уже сообщили: Ваша рекурсивная процедура работать не будет. Т.е. в конце концов сработает, но придётся немножко подождать, что-нибудь порядка $10^{10000}$ лет. Поскольку объём вычислений при прямом вычислении определителя -- порядка $n!$.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 14:35 


21/07/11
105
Как же тогда быть?

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 14:47 
Заслуженный участник


11/05/08
32166
hello19 в сообщении #470551 писал(а):
Как же тогда быть?

Застрелиться. А затем реализовывать метод Гаусса (как Вам опять же уже рекомендовали).

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 14:48 


21/07/11
105
код не могли бы кинуть

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 15:04 
Заслуженный участник


11/05/08
32166
Не мог бы. Во-первых, Вам там что-то уже кидали. А во-вторых, почитайте наконец какой-нибудь учебник по линейной алгебре -- алгоритм там достаточно примитивный.

Только имейте в виду, что 3638 -- это уже в некотором смысле предел. И матрицу придётся хранить в памяти (необходимую сотню мегабайт как-нибудь выделить, наверное, можно), а не на диске; тогда вычисления займут несколько секунд. Если же размер будет в сотню тысяч, на которую Вы замахнулись, то никакой универсальный способ решения практически не будет работать: даже если б матрица хранилась в памяти -- понадобилось бы порядка миллиона секунд, т.е. порядка трёхсот часов. Но в памяти она не уместится, а свопинг отнимет ещё ччёрт знает сколько времени.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 15:13 


21/07/10
555
ewert в сообщении #470561 писал(а):
Не мог бы. Во-первых, Вам там что-то уже кидали. А во-вторых, почитайте наконец какой-нибудь учебник по линейной алгебре -- алгоритм там достаточно примитивный.



Учебник надо читать не по алгебре, а по выч.мату - для матрицы таких размеров наивные алгоритмы не подойдут.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 15:35 
Заслуженный участник


11/05/08
32166

(Оффтоп)

alex1910 в сообщении #470564 писал(а):
для матрицы таких размеров наивные алгоритмы не подойдут.

а ТС ненаивные тем более не помогут, коль скоро ему и в наивных-то разбираться лень

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 16:45 


21/07/10
555
ewert в сообщении #470573 писал(а):

(Оффтоп)

alex1910 в сообщении #470564 писал(а):
для матрицы таких размеров наивные алгоритмы не подойдут.

а ТС ненаивные тем более не помогут, коль скоро ему и в наивных-то разбираться лень



(Оффтоп)

C ТС всем все ясно (пора банить за откровенное желание халявы:) ) - сообщение было скорее для Вас, чем для ТС: обратить матрицу общего вида миллион на миллион на персоналке за несколько минут можно.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 16:49 
Заслуженный участник


11/05/08
32166
alex1910 в сообщении #470588 писал(а):
обратить матрицу общего вида миллион на миллион на персоналке за несколько минут можно.

Эт вряд ли. Начнём с простого: где Вы собираетесь просто хранить этот десяток терабайт?...

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 17:06 


21/07/10
555
ewert в сообщении #470589 писал(а):
alex1910 в сообщении #470588 писал(а):
обратить матрицу общего вида миллион на миллион на персоналке за несколько минут можно.

Эт вряд ли. Начнём с простого: где Вы собираетесь просто хранить этот десяток терабайт?...


Ну, диски по три терабайта в продаже есть - из них можно набрать массив.

Ладно, урежу лосося: Ваша арифметика, полагаю, в том, что матрицу 100.000 на 100.000 можно обратить за C*10^15 операций, если положить на С, процессор и обращения к диску, получаем 10^6 "секунд" при частоте 1ГГЦ --> 277 часов. Отсюда Вы 300 часов взяли?

Однако есть методы, когда матрица "режется" и удается обратить большую матрицу, поработав с кучей малых. При этом сложность получается сильно меньше, чем n-куб. Например,
здесь http://www.mathnet.ru/php/archive.phtml ... n_lang=rus
авторы утверждают, что смогли обратить большую матрицу довольно быстро.
Какое железо они использовали - не знаю, но не что-то заоблачное.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение22.07.2011, 19:22 
Заслуженный участник


11/05/08
32166
alex1910 в сообщении #470595 писал(а):
Ну, диски по три терабайта в продаже есть - из них можно набрать массив.

Три не знаю; вроде как верхнеходовым товаром считается два (Вы ведь про "персоналку" говорили, да?...). Впрочем, это непринципиально. Принципиально другое: подкачивать-то всё равно придётся, и многократно придётся. Между тем случайный доступ к диску -- порядка миллисекунды; т.е. я не помню, каков он на сегодняшний день, но сильно порядок уменьшиться точно не мог -- тут уж чисто механические ограничения.

alex1910 в сообщении #470595 писал(а):
277 часов. Отсюда Вы 300 часов взяли?

Так это ж одно и то же.

alex1910 в сообщении #470595 писал(а):
авторы утверждают, что смогли обратить большую матрицу довольно быстро.Какое железо они использовали - не знаю, но не что-то заоблачное.

Я в чудеса не верю. Если "точное" (в пределах погрешностей округления, кстати, а об этом уж отдельный разговор) решение требует порядка $O(n^3)$ -- то так оно и будет при любых ухищрениях. Конечно, можно попытаться распараллелить (тот же метод Гаусса потенциально даёт возможность снизить за счёт распараллеливания трудоёмкость на порядок, до $O(n^2)$, теорекхтицски); но для персоналки это выглядит нелепо.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение23.07.2011, 00:26 


21/07/10
555
Разумеется, 277 и 300 - одно и то же. Я спрашивал, так ли Вы оценку времени получили?

Чудо, не чудо, решение, разумеется, неточное, (итерации с каким-то порогом останова) невязка что-то порядка 10^(-5). (только не спрашивайте, по какой норме они невязку считали - не знаю). Но нагло врать в опубликованной в приличном месте статье авторы бы не стали.
Если с чем и намухлевали, то с подобором матрицы, которая хорошо "жмется".
Хотите - разбирайтесь, я дал ссылку.

 Профиль  
                  
 
 Re: Почему то не могу считать матрицу
Сообщение24.07.2011, 00:22 


14/10/09
34
Что касается матрицы из статьи, то там все верно. Только нужно учесть тот факт, что эта матрица достаточно своеобразная. Она получается после дискретизации гиперсингулярного интегрального уравнения и, грубо говоря, её элементами являются функции вида $\frac{1}{r^2}$. Поскольку эта функция достаточно быстро убывает, то эту матрицу можно приближенно представить блочными матрицами гораздо меньшей размерности.

А что касается исходной задачи обращения матрицы $10^6 \times 10^6$, то в общем случае задача практически не решаемая в разумное время. Но если матрица обладает какими-нибудь свойствами, то задачу можно решить. Например, такие матрицы часто получаются при решении УРЧП методом конечных элементов. Но в этом случае матрицы разряженные и с диагональным преобладанием. Обычно их хранят специальным образом и используют итерационные алгоритмы.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group