ค้นหาดีเทอร์มิแนนต์สูงสุดสำหรับเมทริกซ์ Toeplitz แต่ละขนาด


14

สำหรับค่าคงที่ n ให้พิจารณาเมทริกซ์ n โดย n Toeplitzด้วยรายการที่เป็น 0 หรือ 1 จุดมุ่งหมายคือการค้นหาดีเทอร์มิแนนต์สูงสุดสำหรับเมทริกซ์ Toeplitz ทั้งหมด

งาน

สำหรับแต่ละnจาก 1 ขึ้นไปเอาท์พุทดีเทอร์มิแนนต์สูงสุดสำหรับเมทริกซ์ Toeplitz ทั้งหมดด้วยรายการซึ่งเป็น 0 หรือ 1 ควรมีเอาต์พุตหนึ่งตัวต่อnซึ่งควรมีดีเทอร์มิแนนต์สูงสุดและเมทริกซ์ตัวอย่างที่มาถึง

คะแนน

คะแนนของคุณใหญ่ที่สุดnรหัสของคุณไปถึงภายใน 2 นาทีบนคอมพิวเตอร์ของฉัน ชี้แจงน้อยรหัสของคุณสามารถทำงานเป็นเวลา 2 นาทีในทั้งหมดนี้ไม่ได้ 2 nนาทีต่อ

เบรกเกอร์

หากสองรายการได้รับnคะแนนเท่ากันผลงานที่ชนะจะเป็นรายการที่ได้คะแนนสูงสุดnในเวลาอันสั้นบนเครื่องของฉัน หากผลงานที่ดีที่สุดสองรายการเท่ากันในเกณฑ์นี้เช่นกันผู้ชนะจะได้รับคำตอบก่อน

ภาษาและห้องสมุด

คุณสามารถใช้ภาษาและไลบรารี่ที่คุณต้องการได้ฟรี ฉันจะต้องสามารถเรียกใช้รหัสของคุณดังนั้นโปรดรวมคำอธิบายแบบเต็มสำหรับวิธีการเรียกใช้ / รวบรวมรหัสของคุณใน linux ถ้าเป็นไปได้ทั้งหมด

My Machineเวลาของฉันจะทำงานบนเครื่องของฉัน นี่คือการติดตั้ง Ubuntu มาตรฐานบนโปรเซสเซอร์ AMD FX-8350 Eight-Core นี่ก็หมายความว่าฉันต้องสามารถเรียกใช้รหัสของคุณได้

คำตอบเล็ก ๆ

สำหรับ n = 1..10 ผลลัพธ์ควรเป็น 1,1,2,3,5,9,32,56,125,315

ลำดับนี้ไม่ได้อยู่ในOEISดังนั้นผู้ชนะจึงได้รับการเสนอรายการใหม่ที่นั่น

รายการที่ผ่านมา

  • n=10 n=11โดย Vioz ในPython
  • n=9โดย Tyilo ในC.
  • n=12โดย Legendre ในJ
  • n=10โดย Tensibai ในR
  • n=14โดย SteelRaven ในC ++
  • n=14โดย RetoKoradi ในC ++

@AlexA คุณพูดถูกและฉันขอโทษ โชคดีที่ปัญหาสองอย่างนั้นคล้ายกันมากดังนั้นเขาควรจะสามารถแก้ไขโค้ดของเขาได้อย่างง่ายดาย

การแก้ปัญหาโดย @Vioz เกิดขึ้นกับลำดับที่ขึ้นต้นด้วย 1, 1, 2, 3, 5, 9, 32 ดังนั้นค่าสำหรับ n = 5 จึงแตกต่างจากรายการที่คุณระบุ เนื่องจากค่าอื่น ๆ ทั้งหมดตรงกันดูเหมือนว่าวิธีแก้ปัญหาอาจถูกต้องและนี่เป็นเพียงการพิมพ์ผิดในคำถาม
Reto Koradi

@RetoKoradi ขอบคุณ แก้ไขแล้ว.

นี่คือ 10 เมทริกซ์ไบนารี Toeplitz ที่เป็นไปได้ที่มีค่าสูงสุดสำหรับn = 1..10: ghostbin.com/paste/axkpa
Tyilo

2
เป็นการสังเกตที่อาจช่วยให้ผู้อื่น แต่ฉันไม่สามารถตรวจสอบเกินกว่า 14 มันปรากฏวิธีการที่เกี่ยวข้องของแถวบนสุดและคอลัมน์แรกของเมทริกซ์ Toeplitz เสมอ 0.4 <= m <= 0.6 สำหรับปัจจัยสูงสุด
MickyT

คำตอบ:


3

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 มาก่อนดังนั้นฉันหวังว่าสิ่งนี้จะรวบรวมและทำงานโดยไม่ต้องผูกปม:

  1. บันทึกรหัสในไฟล์ที่มีนามสกุลเช่น.cppoptim.cpp
  2. gcc -Ofast optim.cpp -lpthread -lstdc++คอมไพล์ด้วย
  3. 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;
}

มีวิธีที่น่าสนใจในการคำนวณดีเทอร์มีแนนต์ของเมทริกซ์จำนวนเต็มโดยใช้เลขคณิตจำนวนเต็มเท่านั้น: LU การสลายตัวในบางฟิลด์ จำกัด ฉันไม่รู้ว่าจะเร็วกว่านี้ไหม
lirtosiast

@ThomasKwa นั่นน่าจะเป็น O (n ^ 3)? มันอาจจะมีประโยชน์สำหรับเมทริกซ์ขนาดใหญ่ที่ความแม่นยำของจุดลอยตัวจะกลายเป็นปัญหา ฉันไม่ได้มองหาวรรณกรรมจริงๆ ฉันค้นหาอย่างรวดเร็วและพบบทความเกี่ยวกับการคำนวณดีเทอร์มิแนนต์ของเมทริกซ์ Toeplitz แต่มีคำถามเปิดมากเกินไปที่ฉันจะยอมรับเวลาที่จะลองและใช้มัน
Reto Koradi

1
@ Lembik ฉันจะลองดูในวันนี้ ฉันเปลี่ยนมันเพื่อจัดการกับขนาดที่ใหญ่ขึ้นสำหรับความท้าทายอื่น ๆ ที่เกี่ยวข้องของคุณเมื่อวานนี้ ไม่สามารถเอาชนะคะแนนสูงสุดสำหรับ n = 30 จนถึงตอนนี้ฮิวริสติกของฉันติดอยู่ต่ำกว่า 5 * 10 ^ 13
Reto Koradi

1
@Lembik ดูpaste.ubuntu.com/11915546สำหรับรหัสและpaste.ubuntu.com/11915532สำหรับผลลัพธ์สูงสุด n = 19
Reto Koradi

1
@Lembik ผลลัพธ์ขึ้นอยู่กับ n = 20 อยู่ที่paste.ubuntu.com/11949738 ตอนนี้พวกเขาแสดงรายการโซลูชันที่เชื่อมโยงทั้งหมดรวมถึงคุณลักษณะเพื่อดูค่าของเส้นทแยงมุมอย่างรวดเร็วและดูว่ามีการไหลเวียนหรือไม่ ค่าสูงสุดสำหรับ m = 18,19,20 เป็นเมทริกซ์หมุนเวียน โปรดตรวจสอบปัจจัยก่อนที่จะเผยแพร่ได้ทุกที่
Reto Koradi

8

J

อัปเดต: ปรับปรุงรหัสเพื่อค้นหามากกว่าครึ่งหนึ่งของค่า ตอนนี้คำนวณได้n=12อย่างสะดวกสบายภายใน 120 วินาที (ลดลงจากยุค 217 เป็น 60 วินาที)

คุณจะต้องติดตั้งJเวอร์ชันล่าสุด

#!/usr/bin/jconsole

dim =: -:@>:@#
take =: i.@dim
rotstack =: |."0 1~ take
toep =: (dim (|."1 @: {."1) rotstack)"1
det =: -/ . * @: toep
ps =: 3 : ',/(0 1 ,"0 1/ ,.y)'
canonical =: #. >: [: #. |. " 1

lss =: 3 : 0
  shape =. (2^y), y
  shape $ ,>{;/(y,2)$0 1
)

ls =: (canonical@:lss) # lss
ans =: >./ @: det @: ls @: <: @: +:

display =: 3 : 0
echo 'n = ';y;'the answer is';ans y
)
display"0 (1 + i.13)
exit''

เรียกใช้และฆ่าเมื่อสองนาทีขึ้น ผลลัพธ์ของฉัน (MBP 2014 - RAM of 16GB):

┌────┬─┬─────────────┬─┐
│n = │1│the answer is│1│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬─┐
│n = │2│the answer is│1│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬─┐
│n = │3│the answer is│2│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬─┐
│n = │4│the answer is│3│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬─┐
│n = │5│the answer is│5│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬─┐
│n = │6│the answer is│9│
└────┴─┴─────────────┴─┘
┌────┬─┬─────────────┬──┐
│n = │7│the answer is│32│
└────┴─┴─────────────┴──┘
┌────┬─┬─────────────┬──┐
│n = │8│the answer is│56│
└────┴─┴─────────────┴──┘
┌────┬─┬─────────────┬───┐
│n = │9│the answer is│125│
└────┴─┴─────────────┴───┘
┌────┬──┬─────────────┬───┐
│n = │10│the answer is│315│
└────┴──┴─────────────┴───┘
┌────┬──┬─────────────┬────┐
│n = │11│the answer is│1458│
└────┴──┴─────────────┴────┘
┌────┬──┬─────────────┬────┐
│n = │12│the answer is│2673│
└────┴──┴─────────────┴────┘

เวลาใช้งานทั้งหมด = 61.83 วินาที


แค่เล่น ๆ

┌────┬──┬─────────────┬────┐
│n = │13│the answer is│8118│
└────┴──┴─────────────┴────┘

สิ่งนี้ใช้เวลาประมาณ 210 วินาทีด้วยตัวมันเอง


1
หมายเหตุถึงผู้ทดสอบ: n = 12ต้องการหน่วยความจำประมาณ 18 GiB
Dennis

นี่เป็นการปรับปรุงที่ดีมาก เอาท์พุทเป็นรถบั๊กเล็กน้อย สำหรับฉันที่ใช้ j64-804 มันจะส่งออก n = 1 สองครั้งดังนั้นมันจึงออกมาทีละหนึ่งตลอดไป

@ Lembik Ah ใช่แล้ว ฉันเพิ่งปรับปรุงรหัส; ลองเรียกใช้อีกครั้งได้ไหม ขอบคุณ! (ฉันได้ตั้งค่าให้คำนวณได้สูงสุดn=13คุณสามารถเปลี่ยน13บรรทัดที่สองเป็นครั้งสุดท้ายเพื่อให้คำนวณได้ตามที่คุณต้องการ)
Legendre

ฉันวิ่งอีกครั้งและยังคงไปถึง 12

@ Lembik อืม .. คุณกำลังบอกว่ามันจะไปถึง 12 ภายในเวลาที่กำหนดและเพิ่มขึ้นถึง 13 ในเวลาหลังจากนั้น (ซึ่งเป็นสิ่งที่ฉันคาดหวัง) หรือว่าจะไม่ได้รับถึง 13 (เช่นโปรแกรมหยุดหลังจาก 12)?
เลอช็องดร์

4

Python 2

นี่เป็นทางออกที่ตรงไปตรงมามากและอาจไม่ชนะการแข่งขัน แต่เฮ้มันใช้งานได้!

ฉันจะให้ภาพรวมอย่างรวดเร็วว่าเกิดอะไรขึ้น

  1. nครั้งแรกที่ผมสร้างทุกแถวเริ่มต้นที่เป็นไปได้สำหรับ ตัวอย่างเช่นเมื่อn=2สิ่งนี้จะสร้างความยาวของอาร์เรย์ 2 n + 1โดยที่แต่ละแถวมีความยาว 2n-1 มันจะมีลักษณะเช่นนี้: [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]].
  2. จากนั้นสำหรับแต่ละแถวเริ่มต้นที่เป็นไปได้เหล่านั้นฉันหมุนnเวลาและแบ่งnรายการแรกเพื่อสร้างเมทริกซ์ที่เหมาะสมและใช้scipyในการคำนวณดีเทอร์มิแนนต์ทั้งหมดในขณะที่ติดตามค่าสูงสุด ในตอนท้ายของเรื่องนี้ฉันก็พิมพ์ค่าสูงสุด, เพิ่มขึ้นทีละn1 และทำต่อไปจนกระทั่งผ่านไป 10 นาที

ในการเปิดใช้งานนี้คุณจะต้องติดตั้งscipy

แก้ไข 1: เปลี่ยนวิธีสร้างแถวเริ่มต้นโดยใช้ itertools.product แทนขอบคุณ Sp3000!

แก้ไข 2: ลบที่เก็บข้อมูลของแถวเริ่มต้นที่เป็นไปได้เพื่อปรับปรุงความเร็วให้น้อยที่สุด

แก้ไข 3: เปลี่ยนเป็นscipyเพื่อควบคุมการdetทำงานได้มากขึ้น

from scipy import linalg
from collections import deque
from time import time
from itertools import product

c=1
t=time()
while 1:
    m=0
    for d in product(range(2),repeat=2*c-1):
        a=deque(d)
        l=[d[0:c]]
        for x in xrange(c-1):
            a.rotate(1)
            l+=[list(a)[0:c]]
        m=max(m,linalg.det(l,overwrite_a=True,check_finite=False))
    print m,'in',time()-t,'s'
    c+=1

นี่คือตัวอย่างบางส่วนของเครื่องที่บ้านของฉัน (i7-4510U, 8GB RAM):

1.0 in 0.0460000038147 s
1.0 in 0.0520000457764 s
2.0 in 0.0579998493195 s
3.0 in 0.0659999847412 s
5.0 in 0.0829999446869 s
9.0 in 0.134999990463 s
32.0 in 0.362999916077 s
56.0 in 1.28399991989 s
125.0 in 5.34999990463 s
315.0 in 27.6089999676 s
1458.0 in 117.513000011 s

ขอบคุณ แต่ฉันคิดว่าคุณตอบคำถามรุ่นเก่าที่ฉันกลัว ตอนนี้เป็นเรื่องเกี่ยวกับเมทริกซ์ Toeplitz และ จำกัด เวลาคือ 2 นาที

4
ฉันเห็น Python golfed มากในเว็บไซต์นี้ซึ่งฉันมักจะลืมไปว่าเพื่อวัตถุประสงค์ทั่วไปจริงๆแล้วมันเป็นภาษาที่อ่านได้
Alex A.

นี่อาจเร่งความเร็วได้อย่างมีนัยสำคัญเพราะมันไม่ได้ใช้ประโยชน์จากข้อเท็จจริงที่ว่ามันเป็นเมทริกซ์ไบนารี
lirtosiast

@ThomasKwa ถ้าฉันซื่อสัตย์ฉันไม่มีความคิดวิธีการใช้ประโยชน์จากที่: P
Kade

อ้างจากเอกสารที่มีจำนวนมาก: "ดีเทอร์มิแนนต์คำนวณผ่านการแยกตัวประกอบ LU โดยใช้ LAPACK ประจำ z / dgetrf" ฉันดู dgetrf และมันบอกว่าใช้ความแม่นยำสองเท่า ขึ้นอยู่กับความแม่นยำของ GPU เดี่ยวของ OP อาจเร็วขึ้น
lirtosiast

4

C ++

Bruteforce ด้วยการใช้ OpenMP สำหรับการขนานและการเพิ่มประสิทธิภาพอย่างง่ายเพื่อหลีกเลี่ยงการประเมินดีเทอร์มิแนนต์สำหรับเมทริกซ์ transposed

$ lscpu
...
Model name:            Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
...
$ g++ -O2 toepl.cpp -fopenmp
$ timeout 2m ./a.out 
1 1
2 1
3 2
4 3
5 5
6 9
7 32
8 56
9 125
10 315
11 1458
12 2673
13 8118
14 22386
#include <cmath>

#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

void updateReverses(vector < int > & reverses) {
  int reversesCnt = reverses.size();
  for(int i = 0; i < reversesCnt; ++i){
    reverses[i] <<= 1;
    reverses.push_back(reverses[i] | 1);
  }
}

const double eps = 1e-9;

double determinant(vector < vector < double > > & matrix) {
  int n = matrix.size();
  double det = 1;
  if(n == 1) return matrix[0][0];
  for(int i = 0; i < n; ++i){
    int p = i;
    for(int j = i + 1; j < n; ++j)
      if(fabs(matrix[j][i]) > fabs(matrix[p][i]))
        p = j;
    if(fabs(matrix[p][i]) < eps)
      return 0;
    matrix[i].swap(matrix[p]);
    if(i != p) det *= -1;
    det *= matrix[i][i];
    matrix[i][i] = 1. / matrix[i][i];
    for(int j = i + 1; j < n; ++j)
      matrix[i][j] *= matrix[i][i];
    for(int j = i + 1; j < n; ++j){
      if(fabs(matrix[j][i]) < eps) continue;
      for(int k = i + 1; k < n; ++k)
        matrix[j][k] -= matrix[i][k] * matrix[j][i];
    }
  }
  return det;
}

int main() {
  vector < int > reverses(1, 0);
  reverses.reserve(1 << 30);
  updateReverses(reverses);
  for(int n = 1;; ++n){
    double res = 0;
    int topMask = 1 << (2 * n - 1);
    vector < vector < double > > matrix(n, vector < double > (n));
#pragma omp parallel for reduction(max:res) firstprivate(matrix) schedule(dynamic,1<<10)
    for(int mask = 0; mask < topMask; ++mask){
      if(mask < reverses[mask]) continue;
      for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
          matrix[i][j] = (mask >> (i - j + n - 1)) & 1;
      res = max(res, determinant(matrix));
    }
    cout << n << ' ' << res << endl;
    updateReverses(reverses);
    updateReverses(reverses);
  }
}

ดูเหมือนว่าคุณอาจจะเข้าสู่ OEIS รายการแรกของคุณในไม่ช้าเว้นแต่จะมีใครคิดไอเดียที่ฉลาด :)

2

รวบรวมกับ:

$ clang -Ofast 52851.c -o 52851

ทำงานด้วย:

$ ./52851

สามารถส่งออกดีเทอร์มิแนนต์สูงสุดn = 1..10ใน ~ 115 วินาทีบนคอมพิวเตอร์ของฉัน

โปรแกรมเพิ่งได้รับดีเทอร์มิแนนต์ทุกตัวที่เป็นไปได้เมทริกซ์ Toeplitz ของขนาดnเมทริกซ์ของเมทริกซ์ขนาด5x5หรือเล็กกว่านั้นจะถูกแคชโดยใช้การบันทึก

ตอนแรกฉันคิดผิดว่าทุก ๆ submatrix ของเมทริกซ์ Toeplitz จะเป็นเมทริกซ์ Toeplitz ด้วยดังนั้นฉันแค่จำ2^(2n-1)ค่าแทนที่จะเป็นค่า2^(n^2)แต่ละnอัน ฉันทำโปรแกรมก่อนที่จะเข้าใจความผิดพลาดดังนั้นการส่งนี้เป็นเพียงการแก้ไขของโปรแกรมนั้น


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>

#define ELEMENTS(x) (sizeof(x) / sizeof(*x))

int *dets[6];

void print_matrix(int n, int c) {
    for(int row = 0; row < n; row++) {
        for(int col = 0; col < n; col++) {
            int j = n - 1 - row + col;
            int val = !!(c & (1 << j));
            printf("%d ", val);
        }
        puts("");
    }
}

int det(int n, uint8_t *m) {
    if(n == 1) {
        return m[0];
    }

    int i = 0;

    if(n < ELEMENTS(dets)) {
        for(int j = 0; j < n * n; j++) {
            i *= 2;
            i += m[j];
        }

        int v = dets[n][i];
        if(v != INT_MIN) {
            return v;
        }
    }

    int v = 0;

    uint8_t *sub = malloc((n - 1) * (n - 1));

    for(int removed = 0; removed < n; removed++) {
        if(m[removed]) {
            uint8_t *p = sub;
            for(int row = 1; row < n; row++) {
                for(int col = 0; col < n; col++) {
                    if(col == removed) {
                        continue;
                    }

                    *p = m[col + row * n];

                    p++;
                }
            }

            v += (removed % 2 == 0? 1: -1) * det(n - 1, sub);
        }
    }

    free(sub);

    if(n < ELEMENTS(dets)) {
        dets[n][i] = v;
    }
    return v;
}

int main(void) {
    for(int i = 2; i < ELEMENTS(dets); i++) {
        int combinations = 1 << (i * i);
        dets[i] = malloc(combinations * sizeof(**dets));
        for(int j = 0; j < combinations; j++) {
            dets[i][j] = INT_MIN;
        }
    }

    puts("1: 1");

    for(int n = 2; n < 65; n++) {
        int vars = 2 * n - 1;
        size_t combinations = 1 << vars;

        int best = -1;
        int max = -1;

        uint8_t *sub = malloc((n - 1) * (n - 1));

        for(int c = 0; c < combinations; c++) {
            int d = 0;
            for(int i = 0; i < n; i++) {
                if(c & (1 << (n - 1 + i))) {
                    uint8_t *p = sub;
                    for(int row = 1; row < n; row++) {
                        for(int col = 0; col < n; col++) {
                            if(col == i) {
                                continue;
                            }

                            int j = n - 1 - row + col;
                            *p = !!(c & (1 << j));

                            p++;
                        }
                    }
                    d += (i % 2 == 0? 1: -1) * det(n - 1, sub);
                }
            }

            if(d > max) {
                max = d;
                best = c;
            }
        }

        free(sub);

        printf("%d: %d\n", n, max);
        //print_matrix(n, best);
    }

    return 0;
}

ดูเหมือนว่าคุณกำลังคำนวณดีเทอร์แนนต์โดยใช้การขยายตัวของผู้เยาว์ สิ่งนี้มีO(n!)ความซับซ้อนดังนั้นคุณจึงควรใช้อัลกอริธึมที่ต่างออกไป
lirtosiast

@ThomasKwa ฉันไม่ทราบว่ามีอัลกอริธึมที่เร็วขึ้นดังนั้นใช่ว่าโซลูชันนี้ค่อนข้างแย่
Tyilo

คุณอาจต้องการใช้LU Decompositionเพื่อค้นหาดีเทอร์มีแนนต์ของเมทริกซ์ มันเป็นO(n^3)ผมเชื่อว่าแม้ว่าจะสามารถทำได้เร็วขึ้นด้วยขั้นตอนวิธีการที่น่าสนใจบาง ฉันเชื่อว่าตัวบิวอินส่วนใหญ่ที่ใช้ที่นี่โดยทั่วไปใช้ตัวแปรของการย่อยสลายเพื่อกำหนดปัจจัย
BrainSteel

@BrainSteel ใช่ฉันดูมัน แต่ฉันอาจไปหาO(n^2)อัลกอริทึมถ้าฉันกำลังปรับปรุงคำตอบของฉัน
Tyilo

ตามการค้นหาของวิกิพีเดียสบาย ๆ ปัจจัยของเมทริกซ์ Toeplitz O(n^2)สามารถกำหนดใน แต่ฉันคิดว่าปัญหาคอขวดของปัญหาคือการค้นหาระหว่างO(4^n)0-1 จำนวนมากnด้วยnเมทริกซ์
Legendre

2

R

คุณจะต้องติดตั้ง R และแพ็คเกจที่อยู่ในรายการ install.packages("package_name")

ใช้งานเวอร์ชันนี้ไม่ถึง 2 นาที (ฉันต้องลองใช้การดัดแปลงแบบขนาน)

library(pracma)
library(stringr)
library(R.utils)
library(microbenchmark)

f <- function(n) {
  #If n is 1, return 1 to avoid code complexity on this special case
  if(n==1) { return(1) }
  # Generate matrices and get their determinants
  dets <- sapply(strsplit(intToBin( 0:(2^n - 1)), ""), function(x) {
              sapply( strsplit( intToBin( 0:(2^(n-1) - 1) ), ""), 
                    function(y) { 
                      det(Toeplitz(x,c(x[1],y))) 
                    })

              })
  #Get the maximum determinant and return it
  res <- max(abs(dets))
  return(res)
}

โทรและส่งออก:

> sapply(1:10,f)
 [1]   1   1   2   3   5   9  32  56 125 315

เกณฑ์มาตรฐานในเครื่องของฉัน:

> microbenchmark(sapply(1:10,f),times=1L)
Unit: seconds
            expr      min       lq     mean   median       uq      max neval
 sapply(1:10, f) 66.35315 66.35315 66.35315 66.35315 66.35315 66.35315     1

สำหรับข้อมูลสำหรับช่วง 1:11 จะใช้เวลา 285 วินาที


1

PARI / GP, n = 11

นี่คือพลังของสัตว์ det(A^T) = det(A)แต่การใช้ประโยชน์จาก ฉันแค่โพสต์มันเพื่อแสดงให้เห็นว่าการข้ามไปมาง่ายเพียงใด บิตต่ำสุดของการb1เก็บเซลล์ซ้ายบนและบิตอื่น ๆ ถือส่วนที่เหลือของแถวบน b2เก็บส่วนที่เหลือของคอลัมน์ด้านซ้าย b2 <= (b1>>1)เราก็บังคับใช้

{ for(n=1,11,
    res=0;
    for(b1=0,2^n-1,
      for(b2=0,b1>>1,
        res=max(res,matdet(matrix(n,n,i,j,bittest(if(i>j,b2>>(i-j-1),b1>>(j-i)),0))));
      )
    );
    print(n" "res);
  )
}

เกี่ยวกับการคำนวณปัจจัย Toeplitz ในO(n^2)เวลา: ในการวิจัยที่ จำกัด ของฉันฉันได้พบกับความต้องการที่ผู้เยาว์หลักชั้นนำทั้งหมดต้องไม่ใช่ศูนย์เพื่อให้อัลกอริทึมในการทำงานซึ่งเป็นอุปสรรคสำคัญสำหรับงานนี้ อย่าลังเลที่จะให้คำแนะนำแก่ฉันหากคุณรู้มากกว่านี้


คุณเห็นกระดาษนี้หรือไม่ scienpress.com/upload/JAMB/Vol%201_1_4.pdf ไม่ชัดเจนสำหรับฉันว่าความซับซ้อนคืออะไร ดูเหมือนจะมีคำศัพท์ค่อนข้างมากสำหรับตัวอย่าง n = 5
Reto Koradi

@RetoKoradi ใช่ฉันเห็นแล้ว ดูเหมือนซับซ้อนไม่ได้เป็นพหุนามพิจารณาว่าเช่นe_{k+1}มี 4 e_kครั้งจำนวนของชิ้นส่วนเป็น มีการละเว้นมากมายในกระดาษ เมทริกซ์แบบกลับด้านได้มีการสลายตัวของ LU หากผู้เยาว์หลักชั้นนำทั้งหมดไม่ใช่ศูนย์ (ขอให้สังเกตตัวส่วนเช่นa_0- โดยนัยพวกเขาจะรับประกันว่าไม่ใช่ศูนย์) เอกลักษณ์มาจาก L เป็นหน่วยสามเหลี่ยม ผู้เขียนยังไม่ได้พูดถึงเสถียรภาพของตัวเลข ในกรณีที่การเชื่อมโยงไม่พร้อมใช้งานบทความคือ "ในการคำนวณปัจจัยของ Toeplitz Matrices" โดย Hsuan-Chu Li (2011)
Mitch Schwartz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.