pthread가있는 C ++
내 컴퓨터에서 1 분 안에 n = 14에 도달합니다. 그러나 이것은 2 코어 노트북 일 뿐이므로 8 코어 테스트 머신이 2 분 안에 n = 15를 완료 할 수 있기를 바랍니다. 내 컴퓨터에서 약 4:20 분이 걸립니다.
나는 정말로 더 효율적인 것을 제안하기를 바랐다. 이 한 가지고 보다 효율적 이진 행렬의 확정을 계산하는 방법이 될 수 있습니다. 결정적 계산에서 +1 및 -1 항을 계산하는 일종의 동적 프로그래밍 접근법을 생각해 내고 싶었습니다. 그러나 그것은 지금까지 꽤 잘 이루어지지 않았습니다.
현상금이 만료되기 때문에 표준 무차별 대입 접근 방식을 구현했습니다.
- 가능한 모든 Toeplitz 행렬을 반복합니다.
- 바뀐 행렬 쌍에서 둘 중 하나를 건너 뜁니다. 행렬은 비트 마스크 값으로 설명되므로 비트 마스크의 반전이 비트 마스크 자체보다 작은 모든 값을 건너 뛰어 간단하게 수행 할 수 있습니다.
- 결정은 교과서 LR 분해로 계산됩니다. 약간의 성능 조정을 제외하고 대학 수치 분석법 책에서 알고리즘을 개선 한 주요 개선점은 더 간단한 피벗 전략을 사용한다는 것입니다.
- 병렬화는 pthread로 수행됩니다. 각 스레드에서 처리 된 값에 대해 일정한 간격을 사용하면로드 밸런싱이 매우 나빠 지므로 몇 가지 스위 즐링을 도입했습니다.
나는 이것을 Mac OS에서 테스트했지만 전에 우분투에서 비슷한 코드를 사용했기 때문에 이것이 문제없이 컴파일되고 실행될 수 있기를 바랍니다.
.cpp확장자 가있는 파일에 코드를 저장하십시오 ( 예 :) optim.cpp.
- 로 컴파일하십시오
gcc -Ofast optim.cpp -lpthread -lstdc++.
- 로 실행하십시오
time ./a.out 14 8. 첫 번째 인수는 최대 값 n입니다. 14 분은 확실히 2 분 안에 끝나야하지만 15 번도 시도해도 좋을 것입니다. 두 번째 인수는 스레드 수입니다. 기계의 코어 수와 동일한 값을 사용하는 것이 일반적으로 좋은 시작이지만 일부 변형을 시도하면 잠재적으로 시간이 향상 될 수 있습니다.
코드를 작성하거나 실행하는 데 문제가 있으면 알려주십시오.
#include <stdint.h>
#include <pthread.h>
#include <cstdlib>
#include <iostream>
static int NMax = 14;
static int ThreadCount = 4;
static pthread_mutex_t ThreadMutex;
static pthread_cond_t ThreadCond;
static int BarrierCount = 0;
static float* MaxDetA;
static uint32_t* MaxDescrA;
static inline float absVal(float val)
{
return val < 0.0f ? -val : val;
}
static uint32_t reverse(int n, uint32_t descr)
{
uint32_t descrRev = 0;
for (int iBit = 0; iBit < 2 * n - 1; ++iBit)
{
descrRev <<= 1;
descrRev |= descr & 1;
descr >>= 1;
}
return descrRev;
}
static void buildMat(int n, float mat[], uint32_t descr)
{
int iDiag;
for (iDiag = 1 - n; iDiag < 0; ++iDiag)
{
float val = static_cast<float>(descr & 1);
descr >>= 1;
for (int iRow = 0; iRow < n + iDiag; ++iRow)
{
mat[iRow * (n + 1) - iDiag] = val;
}
}
for ( ; iDiag < n; ++iDiag)
{
float val = static_cast<float>(descr & 1);
descr >>= 1;
for (int iCol = 0; iCol < n - iDiag; ++iCol)
{
mat[iCol * (n + 1) + iDiag * n] = val;
}
}
}
static float determinant(int n, float mat[])
{
float det = 1.0f;
for (int k = 0; k < n - 1; ++k)
{
float maxVal = 0.0f;
int pk = 0;
for (int i = k; i < n; ++i)
{
float q = absVal(mat[i * n + k]);
if (q > maxVal)
{
maxVal = q;
pk = i;
}
}
if (pk != k)
{
det = -det;
for (int j = 0; j < n; ++j)
{
float t = mat[k * n + j];
mat[k * n + j] = mat[pk * n + j];
mat[pk * n + j] = t;
}
}
float s = mat[k * n + k];
det *= s;
s = 1.0f / s;
for (int i = k + 1; i < n; ++i)
{
mat[i * n + k] *= s;
for (int j = k + 1; j < n; ++j)
{
mat[i * n + j] -= mat[i * n + k] * mat[k * n + j];
}
}
}
det *= mat[n * n - 1];
return det;
}
static void threadBarrier()
{
pthread_mutex_lock(&ThreadMutex);
++BarrierCount;
if (BarrierCount <= ThreadCount)
{
pthread_cond_wait(&ThreadCond, &ThreadMutex);
}
else
{
pthread_cond_broadcast(&ThreadCond);
BarrierCount = 0;
}
pthread_mutex_unlock(&ThreadMutex);
}
static void* threadFunc(void* pData)
{
int* pThreadIdx = static_cast<int*>(pData);
int threadIdx = *pThreadIdx;
float* mat = new float[NMax * NMax];
for (int n = 1; n <= NMax; ++n)
{
uint32_t descrRange(1u << (2 * n - 1));
float maxDet = 0.0f;
uint32_t maxDescr = 0;
uint32_t descrInc = threadIdx;
for (uint32_t descrBase = 0;
descrBase + descrInc < descrRange;
descrBase += ThreadCount)
{
uint32_t descr = descrBase + descrInc;
descrInc = (descrInc + 1) % ThreadCount;
if (reverse(n, descr) > descr)
{
continue;
}
buildMat(n, mat, descr);
float det = determinant(n, mat);
if (det > maxDet)
{
maxDet = det;
maxDescr = descr;
}
}
MaxDetA[threadIdx] = maxDet;
MaxDescrA[threadIdx] = maxDescr;
threadBarrier();
// Let main thread output results.
threadBarrier();
}
delete[] mat;
return 0;
}
static void printMat(int n, float mat[])
{
for (int iRow = 0; iRow < n; ++iRow)
{
for (int iCol = 0; iCol < n; ++iCol)
{
std::cout << " " << mat[iRow * n + iCol];
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int main(int argc, char* argv[])
{
if (argc > 1)
{
NMax = atoi(argv[1]);
if (NMax > 16)
{
NMax = 16;
}
}
if (argc > 2)
{
ThreadCount = atoi(argv[2]);
}
MaxDetA = new float[ThreadCount];
MaxDescrA = new uint32_t[ThreadCount];
pthread_mutex_init(&ThreadMutex, 0);
pthread_cond_init(&ThreadCond, 0);
int* threadIdxA = new int[ThreadCount];
pthread_t* threadA = new pthread_t[ThreadCount];
for (int iThread = 0; iThread < ThreadCount; ++iThread)
{
threadIdxA[iThread] = iThread;
pthread_create(threadA + iThread, 0, threadFunc, threadIdxA + iThread);
}
float* mat = new float[NMax * NMax];
for (int n = 1; n <= NMax; ++n)
{
threadBarrier();
float maxDet = 0.0f;
uint32_t maxDescr = 0;
for (int iThread = 0; iThread < ThreadCount; ++iThread)
{
if (MaxDetA[iThread] > maxDet)
{
maxDet = MaxDetA[iThread];
maxDescr = MaxDescrA[iThread];
}
}
std::cout << "n = " << n << " det = " << maxDet << std::endl;
buildMat(n, mat, maxDescr);
printMat(n, mat);
threadBarrier();
}
delete[] mat;
delete[] MaxDetA;
delete[] MaxDescrA;
delete[] threadIdxA;
delete[] threadA;
return 0;
}