난 Numerical Recipes 책에 설명 된 루틴을 기반으로 Jacobi 알고리즘을 구현했지만 openmp를 사용하여 병렬화하려고하므로 매우 큰 행렬을 사용하려고합니다. openmp를 사용하여 eigen C++을 사용하는 Jacobi 알고리즘의 병렬화
//#pragma omp parallel for private (ip,g,h,t,theta,c,s,tau)
//#pragma omp parallel for private (g,h,t,theta,c,s,tau)
가에서 내 시도입니다
void ROTATE(MatrixXd &a, int i, int j, int k, int l, double s, double tau)
{
double g,h;
g=a(i,j);
h=a(k,l);
a(i,j)=g-s*(h+g*tau);
a(k,l)=h+s*(g-h*tau);
}
void jacobi(int n, MatrixXd &a, MatrixXd &v, VectorXd &d)
{
int j,iq,ip,i;
double tresh,theta,tau,t,sm,s,h,g,c;
VectorXd b(n);
VectorXd z(n);
v.setIdentity();
z.setZero();
#pragma omp parallel for
for (ip=0;ip<n;ip++)
{
d(ip)=a(ip,ip);
b(ip)=d(ip);
}
for (i=0;i<50;i++)
{
sm=0.0;
for (ip=0;ip<n-1;ip++)
{
#pragma omp parallel for reduction (+:sm)
for (iq=ip+1;iq<n;iq++)
sm += fabs(a(ip,iq));
}
if (sm == 0.0) {
break;
}
if (i < 3)
tresh=0.2*sm/(n*n);
else
tresh=0.0;
#pragma omp parallel for private (ip,g,h,t,theta,c,s,tau)
for (ip=0;ip<n-1;ip++)
{
//#pragma omp parallel for private (g,h,t,theta,c,s,tau)
for (iq=ip+1;iq<n;iq++)
{
g=100.0*fabs(a(ip,iq));
if (i > 3 && (fabs(d(ip))+g) == fabs(d[ip]) && (fabs(d[iq])+g) == fabs(d[iq]))
a(ip,iq)=0.0;
else if (fabs(a(ip,iq)) > tresh)
{
h=d(iq)-d(ip);
if ((fabs(h)+g) == fabs(h))
{
t=(a(ip,iq))/h;
}
else
{
theta=0.5*h/(a(ip,iq));
t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0)
{
t = -t;
}
c=1.0/sqrt(1+t*t);
s=t*c;
tau=s/(1.0+c);
h=t*a(ip,iq);
#pragma omp critical
{
z(ip)=z(ip)-h;
z(iq)=z(iq)+h;
d(ip)=d(ip)-h;
d(iq)=d(iq)+h;
a(ip,iq)=0.0;
for (j=0;j<ip;j++)
ROTATE(a,j,ip,j,iq,s,tau);
for (j=ip+1;j<iq;j++)
ROTATE(a,ip,j,j,iq,s,tau);
for (j=iq+1;j<n;j++)
ROTATE(a,ip,j,iq,j,s,tau);
for (j=0;j<n;j++)
ROTATE(v,j,ip,j,iq,s,tau);
}
}
}
}
}
}
}
나는 계산의 대부분을 수행하는 루프 코드에 삽입 모두 의견을 병렬화하고 싶었다. 불행히도 둘 다 잘못된 결과를 산출하게됩니다. 나는 문제가이 블록에있을 수 있습니다 의심 :
z(ip)=z(ip)-h;
z(iq)=z(iq)+h;
d(ip)=d(ip)-h;
d(iq)=d(iq)+h;
축적의 일반적으로 이런 종류는 감소를 필요로하기 때문하지만, 각 스레드가 배열의 다른 부분에 접근하기 때문에,이 특정 아닙니다.
OpenMP로 작업하기 시작한 이래로 올바른 병렬 처리를 수행하고 있는지 확실하지 않습니다. 따라서 제안이나 권장 사항도 환영받을 것입니다.
Sidenote : Eigen의 SelfAdjointEigenSolver를 포함하여 eigenvalue 및 eigenvector 결정에 더 빠른 알고리즘이 있지만 고유 벡터에 필요한 정밀도를 제공하지 못하는 점을 알고 있으며이 알고리즘은 있습니다.
미리 감사드립니다.
편집 : 나는 4096x4096 크기의 시스템에 대한 계산 시간을 줄이지 못하기 때문에 양자 물리학자가 제공 한 답을 정정하는 것으로 생각했습니다. 어쨌든 코드를 수정하여 제대로 작동하도록 만들었습니다. 그리고 아마도 충분히 큰 시스템을 사용하기 위해 사용할 수있을 것입니다.
의
의 #pragma OMP가 실제로 계산 시간을 줄일 수 있을지 테스트하는 타이머의 사용을 권합니다.
이 코드를 확인하고 실행하지는 않았지만'ROTATE' 함수가 스레드간에 경합을 일으킨 것 같습니다. 그것을 증명하기 위해'#pragma omp critical {...}'을 넣을 수 있습니다. 또한, C89를 준수해야 할 필요가 없다면 (C++을 사용하고 있기 때문에 ...) ... 개인적으로 매개 변수의 범위를 가장 좁은 범위로 줄이는 것이 훨씬 쉽다는 것을 개인적으로 /보다 의미 론적으로 분명하게 만듭니다. – cjhanks
사이드 노트에 관해서, 왜'SelfAdjointEigenSolver'가 당신에게 예상 정확성을주지 않는지 알아내는 것이 좋을 것입니다. 이를 위해 자급 자족 형 예제 또는 문제가있는 매트릭스 중 하나를 게시/전송하여 당사 측에서 조사 할 수 있습니까? (거의 모든 Eigen의 헤더 파일에서 이메일을 찾을 수 있습니다). 감사. – ggael
메타 질문 : 왜 당신 자신을 써주시겠습니까? 기존의 최적화 된 수학 라이브러리 중 하나를 사용하십시오. 인텔 MKL은 https://software.intel.com/en-us/articles/free-mkl에 무료로 제공되며 Jacobi 기능을 포함합니다. https://software.intel.com/en-us/node/522101 필자는 이들이 병렬화되었는지는 모르지만 MKL의 다른 부분은 확실합니다. ("최고의 코드는 작성하지 않아도되는 코드입니다.") (FWIW는 Intel에서 근무하지만 MKL에서는 근무하지 않습니다.) –