2014 dxdy logo

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

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




Начать новую тему Ответить на тему
 
 Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение16.04.2023, 22:10 


25/07/19
24
Здравствуйте, есть задача, решаемая методом конечных элементов, которая сводится к обобщенной задаче собственных значений $Ax=\lambda Bx$ с трехдиагональными, симметричными матрицами. Пишу на $C/C++$ в Visual Studio 2022, для решения используется LAPACK, а именно ф-я: LAPACKE_dggev, а также библиотека Eigen (GeneralizedEigenSolver).
Мой вопрос связан с тем, что вычисления для матриц 2000 $\times$ 2000 в первом случае (CLAPACK) заняли 40 (!) минут, во втором случае (Eigen) больше часа. У меня это вызывает беспокойство, учитывая, что на Python решение данной задачи занимает несколько минут. Полученные собственные числа совпадают в обоих случаях и похожи на правду. Я с таким сталкиваюсь впервые и поэтому даже не знаю в какую сторону двигаться, чтобы искать решение, поэтому буду рад любым версиям, объясняющим такое замедление.

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение16.04.2023, 22:14 
Заслуженный участник
Аватара пользователя


16/07/14
9416
Цюрих
Для начала - проверьте, что библиотеки собраны с оптимизацией. И что долго выполняется именно эта функция (простейший вариант - позвать её дважды).
И 40 минут - это одно вычисление, или всё вместе?

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение16.04.2023, 22:45 


25/07/19
24
1) Для LAPACK я использую готовое решение для VS отсюда https://icl.utk.edu/lapack-for-windows/lapack/index.html#lapacke, там все уже собрано, так что не могу ответить.
2) Да, проблема явно в ней, в коде больше ничего нет, только заполнение этих матриц числами, просто арифметические операции, printf перед и после нее это вроде подтверждают.
3) 40 минут - это на всю программу, но, как писал выше, больше код ничего производительного не делает, так что такое время уходит только на вычисления.

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение16.04.2023, 22:52 
Заслуженный участник
Аватара пользователя


16/07/14
9416
Цюрих
Т.е. один вызов занимает 40 минут?
Проверьте всё-таки, что будет если сделать несколько вызовов (можно на матрице меньшего размера, чтобы не ждать часами), это дешевый способ проверить что действительно ничего не перепутано.
(ну и желательно покажите релевантную часть кода на плюсах и питоне)

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение17.04.2023, 00:05 


25/07/19
24
Код небольшой, поэтому прикреплю весь, там решается ур-е Шредингера для одномерной ямы методом конечных элементов. Есть две матрицы, они собираются стандартным образом, затем вызывается ф-я библиотечная, выводятся собственные числа отрицательные, а в файл пишутся собственные ф-ии. На питоне, к сожалению, кода нет, так как он не мой, но сам видел, что задача не должна решатся 40 минут. Да, 40 минут на один вызов выходит.

код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include "lapacke.h"

/* Auxiliary routines prototypes */
extern void print_matrix(char* desc, lapack_int m, lapack_int n, double* a, lapack_int lda);
extern void print_matrix_int(char* desc, lapack_int m, lapack_int n, lapack_int* a, lapack_int lda);
extern void print_vector(char* desc, lapack_int n, double* a);
extern void print_vector_int(char* desc, lapack_int n, lapack_int* a);

extern double a_f(lapack_int k, lapack_int i, lapack_int j);
extern double b_f(lapack_int k, lapack_int i, lapack_int j);

extern void eig_values();

/* Parameters */
#define NN 500          // number of elements
#define M (NN+1)         // number of nodes
#define A 10.            // radius
#define h (2*A/NN)       // lattice step
#define V0 12            // extern potential (default: 12)

double MainMatrix[M * M];
double RightSideMatrix[M * M];
double X[M];
double V[M - 1];                      // Potential
lapack_int L[2 * (M - 1)];            // Matrix of the Nodes

lapack_int INFO = 0;

double ALPHAR[M], ALPHAI[M], BETA[M];
double VL[M * M], VR[M * M];
double EIG[M];

/* Main program */
int main() {

    //----------------------------------------------------------------------------------//

    for (int i = 0; i < M; ++i) { X[i] = h * i - A; }

    for (int i = 0; i < NN; ++i) {
        if (abs((X[i] + X[i + 1]) / 2) < 1)
            V[i] = -V0;
        else V[i] = 0;
    }

    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < M; ++j) {
            MainMatrix[M * i + j] = 0;
            RightSideMatrix[M * i + j] = 0;
        }
    }
   
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < M; ++j)
            L[i * NN + j] = j + i;

    //print_matrix_int("L\n", 2, NN, L, NN);

    for (int k = 0; k < M - 1; ++k)
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j) {
                MainMatrix[L[i * NN + k] * M + L[j * NN + k]] += a_f(k, i, j);
                RightSideMatrix[L[i * NN + k] * M + L[j * NN + k]] += b_f(k, i, j);
            }

    // Correcting the equations (first and last)

    for (int j = 0; j < M; ++j) {
        MainMatrix[M * 0 + j] = 0;
        MainMatrix[M * (M - 1) + j] = 0;
        RightSideMatrix[M * 0 + j] = 0;
        RightSideMatrix[M * (M - 1) + j] = 0;
    }

    MainMatrix[0] = 1;
    MainMatrix[M * (M - 1) + M - 1] = 1;

    //print_matrix("Main Matrix\n", M, M, MainMatrix, M);

    //print_matrix("Right Matrix\n", M, M, RightSideMatrix, M);

    printf("Before LAPACKE function\n");

    INFO = LAPACKE_dggev(LAPACK_ROW_MAJOR, 'N', 'V', M, MainMatrix, M, RightSideMatrix, M, ALPHAR, ALPHAI, BETA, VL, M, VR, M);
    printf("After LAPACKE function\n");
   
    eig_values();

    if (INFO == 0) printf("Ok\n");
    else printf("INFO = %d\n", INFO);

    FILE* file = fopen("FEM.txt", "w+");

    printf("Negative eigenvalues: ");
    for (int i = 0; i < M; ++i) {
        fprintf(file, " %6.2f", X[i]);
        for (int j = 0; j < M; ++j) {
            if (EIG[j] < 0) {                                 // write only eigenvectors with NEGATIVE eigenvalues...
                fprintf(file, " %6.2f", VR[i * M + j]);
            }
        }
        if (EIG[i] < 0) {
            printf(" %8.4f", EIG[i]);
        }
        fprintf(file, "\n");
    }
    printf("\n");

    fclose(file);

    //----------------------------------------------------------------------------------//

    exit(0);
}

void print_matrix(char* desc, lapack_int m, lapack_int n, double* a, lapack_int lda) {
    lapack_int i, j;
    printf("\n %s\n", desc);
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) printf(" %6.2f", a[i * lda + j]);
        printf("\n");
    }
}

void print_matrix_int(char* desc, lapack_int m, lapack_int n, lapack_int* a, lapack_int lda) {
    lapack_int i, j;
    printf("\n %s\n", desc);
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) printf(" %6d", a[i * lda + j]);
        printf("\n");
    }
}

void print_vector(char* desc, lapack_int n, double* a) {
    lapack_int j;
    printf("\n %s\n", desc);
    for (j = 0; j < n; j++)
        printf(" %6.2f", a[j]);
    printf("\n");
}

void print_vector_int(char* desc, lapack_int n, lapack_int* a) {
    lapack_int j;
    printf("\n %s\n", desc);
    for (j = 0; j < n; j++)
        printf(" %6i", a[j]);
    printf("\n");
}

double a_f(lapack_int k, lapack_int i, lapack_int j) {
    if (i == j) {
        return 1. / h + (2. / 3) * V[k] * h;
    }
    else
        return -1. / h + (1. / 3) * V[k] * h;
}

double b_f(lapack_int k, lapack_int i, lapack_int j) {
    if (i == j) {
        return (+2. / 3) * h;
    }
    else
        return (+1. / 3) * h;
}

void eig_values() {
    for (int i = 0; i < M; ++i) {
        EIG[i] = ALPHAR[i] / BETA[i];
    }
}
 

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение17.04.2023, 02:02 
Заслуженный участник
Аватара пользователя


16/07/14
9416
Цюрих
На моей машине этот код отрабатывает за 0.6с и выдает -11.1520 -8.6534 -4.6963 -0.2158 - такие числа и должны быть?
Если да, то проблемы почти наверняка в сборке lapack.
ValfennayaVaflaya в сообщении #1589974 писал(а):
for (int i = 0; i < 2; ++i)
for (int j = 0; j < M; ++j)
L[i * NN + j] = j + i;
А вот тут у Вас UB. Вряд ли это влияет в данном случае, но всё равно нехорошо.

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение17.04.2023, 06:38 
Заслуженный участник


18/09/21
1771
mihaild в сообщении #1589978 писал(а):
А вот тут у Вас UB. Вряд ли это влияет в данном случае, но всё равно нехорошо.
Там за границы массива вылезает при $i=1$ и $j=M-1$.
Сам массив имеет размер $2(M-1)$, последний индекс $2(M-1)-1$.

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение17.04.2023, 13:32 


25/07/19
24
Да, числа такие же, но у меня вычисления занимают 10 секунд. Ошибка с выходом за пределы массива случайно получилась при копировании кода сюда, просто менял названия переменных для удобства и стер единицу. Хорошо, тогда буду разбираться как собирать самому lapack, спасибо.

 Профиль  
                  
 
 Re: Медленное выполнение программы C/C++ c библ. LAPACK, Eigen
Сообщение12.05.2023, 16:29 


23/02/23
145
пользуйте DSBGV и будет вам в много порядков меньше арифметическая сложность

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

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



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

Сейчас этот форум просматривают: granit201z


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

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