Tìm định thức tối đa cho mỗi kích thước ma trận Toeplitz


14

Đối với một n cố định, hãy xem xét các ma trận n by n Toeplitz với các mục nhập là 0 hoặc 1. Mục đích là để tìm định thức tối đa trên tất cả các ma trận Toeplitz như vậy.

Bài tập

Đối với mỗi ntừ 1 trở lên, xuất ra định thức tối đa trên tất cả n ma trận Toeplitz với các mục nhập là 0 hoặc 1. Nên có một đầu ra cho mỗi nđịnh mức tối đa và cũng là một ma trận ví dụ đạt tới nó.

Ghi bàn

Điểm của bạn là lớn nhất nmà mã của bạn nhận được trong 2 phút trên máy tính của tôi. Để làm rõ một chút, mã của bạn có thể chạy tổng cộng 2 phút, đây không phải là 2 phút mỗi n.

Máy cắt cà vạt

Nếu hai mục có cùng nsố điểm thì mục chiến thắng sẽ là mục đạt được mức cao nhất ntrong thời gian ngắn nhất trên máy của tôi. Nếu hai mục tốt nhất bằng nhau trên tiêu chí này thì người chiến thắng sẽ là câu trả lời được gửi đầu tiên.

Ngôn ngữ và thư viện

Bạn có thể sử dụng bất kỳ ngôn ngữ và thư viện có sẵn miễn phí nào bạn muốn. Tôi phải có khả năng chạy mã của bạn, vì vậy vui lòng bao gồm một lời giải thích đầy đủ về cách chạy / biên dịch mã của bạn trong linux nếu có thể.

Máy của tôi Thời gian sẽ được chạy trên máy của tôi. Đây là bản cài đặt Ubuntu tiêu chuẩn trên Bộ xử lý tám lõi AMD FX-8350. Điều này cũng có nghĩa là tôi cần để có thể chạy mã của bạn.

Câu trả lời nhỏ

Với n = 1..10, các đầu ra phải là 1,1,2,3,5,9,32,56,125,315

Trình tự này không có trong OEIS và vì vậy mục chiến thắng cũng được đề xuất một mục mới ở đó.

Bài dự thi cho đến nay

  • n=10 n=11bởi Vioz trong Python
  • n=9bởi Tyilo ở C
  • n=12bởi Legendre trong J
  • n=10bởi Tensibai ở R
  • n=14bởi SteelRaven trong C ++
  • n=14bởi RetoKoradi trong C ++

@AlexA. Bạn nói đúng và tôi đã xin lỗi. May mắn thay, hai vấn đề rất giống nhau nên anh ấy có thể dễ dàng sửa đổi mã của mình.

Giải pháp của @Vioz đưa ra một chuỗi bắt đầu bằng 1, 1, 2, 3, 5, 9, 32. Vì vậy, giá trị cho n = 5 khác với những gì bạn liệt kê. Vì tất cả các giá trị khác khớp nhau, có vẻ như giải pháp có thể đúng và đây chỉ là một lỗi đánh máy trong câu hỏi?
Reto Koradi

@RetoKoradi Cảm ơn bạn. Đã sửa.

Dưới đây là 10 ma trận Toeplitz nhị phân có thể có với các định thức tối đa cho n = 1..10: ghostbin.com/paste/axkpa
Tyilo

2
Là một quan sát có thể giúp người khác nhưng tôi không thể xác minh ngoài 14. Nó xuất hiện phương tiện tương ứng của hàng trên cùng và cột đầu tiên của ma trận Toeplitz luôn là 0,4 <= m <= 0,6 cho định thức tối đa.
MickyT

Câu trả lời:


3

C ++ với pthread

Điều này được n = 14 chỉ trong chưa đầy 1 phút trên máy của tôi. Nhưng vì đó chỉ là một máy tính xách tay 2 lõi, tôi hy vọng rằng máy thử nghiệm 8 lõi có thể hoàn thành n = 15 trong dưới 2 phút. Mất khoảng 4:20 phút trên máy của tôi.

Tôi đã thực sự hy vọng để đưa ra một cái gì đó hiệu quả hơn. Hiện đã phải là một cách để tính toán quyết tâm của một ma trận nhị phân hiệu quả hơn. Tôi muốn đưa ra một số cách tiếp cận lập trình động, tính các số hạng +1 và -1 trong phép tính xác định. Nhưng nó vẫn chưa đến được với nhau cho đến nay.

Vì tiền thưởng sắp hết hạn, tôi đã thực hiện phương pháp vũ phu tiêu chuẩn:

  • Lặp lại tất cả các ma trận Toeplitz có thể.
  • Bỏ qua một trong hai trong mỗi cặp ma trận chuyển vị. Vì ma trận được mô tả bởi các giá trị bitmask, điều này rất đơn giản để thực hiện bằng cách bỏ qua tất cả các giá trị trong đó độ đảo ngược của bitmask nhỏ hơn chính bitmask.
  • Việc xác định được tính toán với phân tách LR sách giáo khoa. Ngoại trừ một số điều chỉnh hiệu suất nhỏ, cải tiến chính mà tôi đã thực hiện đối với thuật toán từ sách phương pháp số đại học của tôi là tôi sử dụng chiến lược xoay vòng đơn giản hơn.
  • Song song được thực hiện với pthreads. Chỉ sử dụng khoảng cách thông thường cho các giá trị được xử lý bởi mỗi luồng gây ra sự cân bằng tải rất xấu, vì vậy tôi đã giới thiệu một số sự thay đổi.

Tôi đã thử nghiệm điều này trên Mac OS, nhưng tôi đã sử dụng mã tương tự trên Ubuntu trước đây, vì vậy tôi hy vọng điều này sẽ biên dịch và chạy mà không gặp trở ngại nào:

  1. Lưu mã trong một tệp có .cppphần mở rộng, ví dụ optim.cpp.
  2. Biên dịch với gcc -Ofast optim.cpp -lpthread -lstdc++.
  3. Chạy với time ./a.out 14 8. Đối số đầu tiên là tối đa n. Chắc chắn 14 sẽ hoàn thành trong vòng dưới 2 phút, nhưng sẽ rất tuyệt nếu bạn có thể thử 15 như vậy. Đối số thứ hai là số lượng chủ đề. Sử dụng cùng giá trị với số lõi của máy thường là một khởi đầu tốt, nhưng thử một số biến thể có khả năng cải thiện thời gian.

Hãy cho tôi biết nếu bạn có bất kỳ vấn đề nào khi xây dựng hoặc chạy mã.

#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;
}

Có một cách thú vị để tính toán định thức của ma trận số nguyên chỉ sử dụng số học số nguyên: phân rã LU trong một số trường hữu hạn (về cơ bản mod một số nguyên tố lớn). Tôi không biết nếu điều này sẽ nhanh hơn.
lirtosiast

@ThomasKwa Đó có lẽ vẫn là O (n ^ 3)? Nó có thể hữu ích cho các ma trận lớn hơn trong đó độ chính xác của dấu phẩy động sẽ trở thành một vấn đề. Tôi đã không thực sự tìm kiếm văn học. Chà, tôi đã làm một cuộc tìm kiếm nhanh, và tìm thấy một bài báo về việc tính toán các yếu tố quyết định của ma trận Toeplitz. Nhưng có quá nhiều câu hỏi mở để tôi dành thời gian thử và thực hiện nó.
Reto Koradi

1
@Lembik Tôi sẽ thử và xem nó sau hôm nay. Tôi đã thay đổi nó để xử lý các kích thước lớn hơn cho thử thách liên quan khác của bạn ngày hôm qua. Không thể đánh bại điểm số cao nhất cho n = 30 cho đến nay, các heuristic của tôi bị kẹt dưới 5 * 10 ^ 13.
Reto Koradi 20/07/2015

1
@Lembik Xem paste.ubfox.com/11915546 để biết mã và paste.ubfox.com/11915532 để biết kết quả lên tới n = 19.
Reto Koradi 21/07/2015

1
@Lembik Các kết quả lên tới n = 20 là tại paste.ubfox.com/11949738 . Bây giờ họ liệt kê tất cả các giải pháp gắn, bao gồm các thuộc tính để nhanh chóng thấy giá trị của đường chéo và liệu chúng có tuần hoàn hay không. Tất cả các cực đại cho m = 18,19,20 là ma trận tuần hoàn. Vui lòng kiểm tra lại các yếu tố quyết định trước khi xuất bản chúng ở bất cứ đâu.
Reto Koradi

8

J

Cập nhật: Cải thiện mã để tìm kiếm hơn một nửa giá trị. Bây giờ tính toán n=12thoải mái trong vòng 120 giây (giảm từ 217 xuống còn 60 giây).

Bạn sẽ cần cài đặt phiên bản J mới nhất .

#!/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''

Chạy cái này và giết khi hai phút là hết. Kết quả của tôi (MBP 2014 - 16GB RAM):

┌────┬─┬─────────────┬─┐
│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│
└────┴──┴─────────────┴────┘

Tổng thời gian chạy = 61,83s.


Chỉ để cho vui

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

Điều này mất khoảng 210 giây trên chính nó.


1
Lưu ý cho người kiểm tra: n = 12cần khoảng 18 GiB bộ nhớ.
Dennis

Đây là một cải tiến rất tốt đẹp. Tuy nhiên, đầu ra hơi lỗi. Đối với tôi, sử dụng j64-804, nó tạo ra n = 1 hai lần để nó vượt ra ngoài một lần nữa.

@Lembik À đúng rồi. Tôi vừa cập nhật mã; bạn có thể thử chạy lại không? Cảm ơn! (Tôi đã đặt nó để tính toán tối đa n=13. Bạn có thể thay đổi dòng 13thứ hai đến dòng cuối cùng để tính toán bất cứ điều gì bạn muốn.)
Legendre

Tôi đã chạy nó một lần nữa và nó vẫn đạt đến 12.

@Lembik Hmm .. bạn đang nói nó đạt 12 trong thời gian giới hạn và đến 13 sau một thời gian (đó là những gì tôi mong đợi), hoặc nó không bao giờ đạt đến 13 (tức là chương trình tạm dừng sau 12)?
Huyền thoại

4

Con trăn 2

Đây là một giải pháp rất đơn giản và có lẽ sẽ không chiến thắng trong cuộc thi. Nhưng này, nó hoạt động!

Tôi sẽ cung cấp một cái nhìn tổng quan nhanh về chính xác những gì đang xảy ra.

  1. Trước tiên tôi tạo mọi hàng bắt đầu có thể cho n. Ví dụ: khi nào n=2, điều này sẽ tạo ra một mảng có chiều dài 2 n + 1 , trong đó mỗi hàng có độ dài 2n-1. Nó sẽ trông như thế này : [[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. Sau đó, với mỗi hàng bắt đầu có thể, tôi xoay vòng nthời gian và cắt các nmục đầu tiên để tạo ma trận thích hợp và sử dụng scipyđể tính toán định thức, tất cả trong khi theo dõi giá trị tối đa. Khi kết thúc việc này, tôi chỉ cần in tối đa, tăng thêm n1 và tiếp tục cho đến khi 10 phút trôi qua.

Để chạy này, bạn sẽ cần cài đặt scipy .

Chỉnh sửa 1: Thay đổi cách các hàng ban đầu được tạo bằng cách sử dụng itertools.product thay vào đó, cảm ơn Sp3000!

Chỉnh sửa 2: Đã xóa bộ nhớ của các hàng bắt đầu có thể để cải thiện tốc độ tối thiểu.

Chỉnh sửa 3: Thay đổi để scipycó nhiều quyền kiểm soát hơn đối với cách detlàm việc.

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

Đây là một số đầu ra mẫu trên máy chủ của tôi (i7-4510U, RAM 8GB):

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

Cảm ơn bạn nhưng tôi nghĩ bạn đã trả lời một phiên bản cũ của câu hỏi tôi sợ. Bây giờ là về ma trận Toeplitz và giới hạn thời gian là 2 phút.

4
Tôi thấy rất nhiều Python chơi gôn trên trang web này đến nỗi tôi thường quên rằng vì mục đích chung, nó thực sự là một ngôn ngữ có thể đọc được.
Alex A.

Điều này có thể được tăng tốc đáng kể, bởi vì nó không tận dụng thực tế rằng đó là một ma trận nhị phân.
lirtosiast

@ThomasKwa Nếu tôi trung thực, tôi không biết làm thế nào để tận dụng điều đó: P
Kade

Trích dẫn từ tài liệu numpy: "Hệ số xác định được tính toán thông qua hệ số LU bằng cách sử dụng thường trình LAPACK z / dgetrf." Tôi nhìn vào dgetrf, và nó nói nó sử dụng độ chính xác gấp đôi; tùy thuộc vào độ chính xác GPU của OP có thể nhanh hơn.
lirtosiast

4

C ++

Bruteforce với việc sử dụng OpenMP để song song hóa và tối ưu hóa đơn giản để tránh đánh giá định thức cho ma trận chuyển vị.

$ 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);
  }
}

Trông giống như bạn có thể sớm được làm entry OEIS đầu tiên của bạn trừ khi ai đó đi lên với một ý tưởng thông minh :)

2

C

Biên dịch với:

$ clang -Ofast 52851.c -o 52851

Chạy với:

$ ./52851

Có thể xuất định thức tối đa n = 1..10trong ~ 115 giây trên máy tính của tôi.

Chương trình chỉ nhận được định thức mỗi ma trận Toeplitz nhị phân có thể có kích thước n, tuy nhiên mọi xác định của ma trận có kích thước 5x5hoặc nhỏ hơn sẽ được lưu trữ bằng cách sử dụng ghi nhớ.

Lúc đầu, tôi đã giả định sai rằng mọi hàm con của ma trận Toeplitz cũng sẽ là ma trận Toeplitz, vì vậy tôi chỉ cần ghi nhớ 2^(2n-1)các giá trị thay vì 2^(n^2)cho mỗi giá trị n. Tôi đã thực hiện chương trình trước khi nhận ra lỗi của mình, vì vậy bài nộp này chỉ là bản sửa lỗi của chương trình đó.


#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;
}

Có vẻ như bạn đang tính toán yếu tố quyết định bằng cách sử dụng mở rộng bởi vị thành niên; điều này có O(n!)độ phức tạp, vì vậy bạn có thể tốt hơn bằng cách sử dụng một thuật toán khác.
lirtosiast

@ThomasKwa Tôi không biết rằng có các thuật toán nhanh hơn, vì vậy, giải pháp này khá tệ.
Tyilo

Bạn có thể muốn xem xét việc sử dụng LU Decysis để tìm định thức của ma trận. Đó là O(n^3), tôi tin rằng, mặc dù có thể được thực hiện nhanh hơn với một số thuật toán thú vị. Tôi tin rằng hầu hết các nội dung được sử dụng ở đây thường sử dụng một biến thể phân rã để thực hiện các định thức.
BrainSteel 11/07/2015

@BrainSteel, vâng tôi đã xem nó, nhưng tôi cũng có thể tìm kiếm O(n^2)thuật toán nếu tôi đang cập nhật câu trả lời của mình.
Tyilo 11/07/2015

Theo một tìm kiếm Wikipedia thông thường, yếu tố quyết định của ma trận Toeplitz có thể được xác định O(n^2). Nhưng tôi nghĩ rằng các nút cổ chai của vấn đề được tìm kiếm trong O(4^n)nhiều 0-1 nbởi nma trận.
Huyền thoại

2

R

Bạn sẽ phải cài đặt R và các gói được liệt kê với install.packages("package_name")

Không có dưới 2 phút trên máy của tôi với phiên bản này (Tôi phải thử với một sửa đổi song song)

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)
}

Gọi và đầu ra:

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

Điểm chuẩn trên máy của tôi:

> 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

Để biết thông tin, đối với phạm vi 1:11, phải mất 285 giây.


1

PARI / GP, n = 11

Đây là lực lượng vũ phu nhưng lợi dụng det(A^T) = det(A) . Tôi chỉ đăng nó để chứng minh việc bỏ qua chuyển đổi dễ dàng như thế nào. Bit thấp nhất b1giữ ô trên cùng bên trái và các bit khác giữ phần còn lại của hàng trên cùng. b2giữ phần còn lại của cột bên trái. Chúng tôi chỉ đơn giản là thi hành 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);
  )
}

Về tính toán các yếu tố quyết định Toeplitz trong O(n^2) kịp thời: Trong nghiên cứu hạn chế của tôi, tôi đã tiếp tục gặp phải một yêu cầu rằng tất cả các vị thành niên chính hàng đầu phải không khác biệt để các thuật toán hoạt động, đó là một trở ngại lớn cho nhiệm vụ này. Hãy cho tôi biết con trỏ nếu bạn biết nhiều về điều này hơn tôi.


Bạn đã thấy bài báo này? scienpress.com/upload/JAMB/Vol%201_1_4.pdf . Tôi không rõ sự phức tạp là gì. Dường như có khá nhiều thuật ngữ cho ví dụ n = 5.
Reto Koradi

@RetoKoradi Vâng, tôi đã thấy điều đó. Có vẻ như sự phức tạp không phải là đa thức, xem xét điều đóe_{k+1} có số lượng thành phần gấp 4 lần e_k. Có nhiều thiếu sót trong bài báo. Một ma trận khả nghịch có phân rã LU nếu tất cả các vị thành niên chính hàng đầu là khác không. (Lưu ý các mẫu số, ví dụ a_0- ngầm định chúng được đảm bảo là khác không.) Tính duy nhất đến từ L là đơn vị tam giác. Tác giả cũng không đề cập đến sự ổn định số. Trong trường hợp liên kết trở nên không có sẵn, bài báo là "Tính toán các yếu tố quyết định của ma trận Toeplitz" của Hsuan-Chu Li (2011).
Mitch Schwartz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.