C ++ พร้อม pthreads
นี่ไปถึง n = 14 ในเวลาไม่ถึง 1 นาทีบนเครื่องของฉัน แต่เนื่องจากเป็นเพียงแล็ปท็อป 2 คอร์ฉันหวังว่าเครื่องทดสอบ 8-core จะเสร็จสิ้น n = 15 ภายในไม่ถึง 2 นาที ใช้เวลาประมาณ 4:20 นาทีในเครื่องของฉัน
ฉันหวังว่าจะได้สิ่งที่มีประสิทธิภาพมากขึ้น ได้มีจะต้องมีวิธีการคำนวณที่กำหนดของเมทริกซ์ไบนารีได้อย่างมีประสิทธิภาพมากขึ้น ฉันต้องการคิดวิธีการเขียนโปรแกรมแบบไดนามิกบางอย่างที่นับ +1 และ 1 เทอมในการคำนวณดีเทอร์มิแนนต์ แต่มันก็ยังไม่ได้มารวมกันจนถึงตอนนี้
เนื่องจากเงินรางวัลกำลังจะหมดอายุฉันจึงใช้วิธีการบังคับแบบเดรัจฉานแบบมาตรฐาน:
- วนรอบเมทริกซ์ Toeplitz ที่เป็นไปได้ทั้งหมด
- ข้ามหนึ่งในสองในแต่ละเมทริกซ์ที่ถูกย้าย เนื่องจากเมทริกซ์นั้นอธิบายด้วยค่า bitmask สิ่งนี้ง่ายต่อการทำโดยการข้ามค่าทั้งหมดโดยที่ reverse ของ bitmask นั้นเล็กกว่า bitmask เอง
- การคำนวณจะคำนวณด้วยการแยกย่อย LR ตำราเรียน ยกเว้นการปรับแต่งเล็กน้อยบางอย่างการปรับปรุงหลักที่ฉันทำกับอัลกอริทึมจากหนังสือวิธีคำนวณเชิงตัวเลขของฉันคือฉันใช้กลยุทธ์เดือยที่เรียบง่ายกว่า
- การทำ Parallelization ด้วย pthreads เพียงแค่ใช้ระยะห่างปกติสำหรับค่าที่ประมวลผลโดยแต่ละเธรดทำให้เกิดภาระในการโหลดที่ไม่ดีมาก
ฉันทดสอบสิ่งนี้บน Mac OS แต่ฉันเคยใช้โค้ดที่คล้ายกันบน Ubuntu มาก่อนดังนั้นฉันหวังว่าสิ่งนี้จะรวบรวมและทำงานโดยไม่ต้องผูกปม:
- บันทึกรหัสในไฟล์ที่มีนามสกุลเช่น
.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;
}