Her boyutta Toeplitz matrisi için maksimum determinant bulun


14

Sabit bir n için, 0 veya 1 girişleri olan n by n Toeplitz matrislerini düşünün . Amaç, tüm bu Toeplitz matrisleri üzerinde maksimum determinant bulmaktır.

Görev

n1'den yukarı doğru her biri için , 0 veya 1 girişleri ile n n'den n Toeplitz matrislerine nmaksimum determinant çıkışı verin .

Puan

Puanınız nkodunuzun bilgisayarımdaki 2 dakika içinde aldığı en büyük puan . Biraz açıklığa kavuşturmak için, kodunuz toplamda 2 dakika çalışabilir, bu başına 2 dakika değildir n.

Kravat kırıcı

İki giriş aynı npuanı alırsa, kazanan giriş nmakinemde en kısa sürede en yüksek olan giriş olacaktır . En iyi iki giriş de bu kritere eşitse, kazanan ilk önce cevap olacaktır.

Diller ve kütüphaneler

Ücretsiz olarak istediğiniz dil ve kütüphaneleri kullanabilirsiniz. Kodunuzu çalıştırabilmeliyim, bu yüzden lütfen mümkünse kodunuzu linux'da nasıl çalıştıracağınızı / derleyeceğinizi tam bir açıklama ekleyin.

Benim Makine zamanlamaları benim makinede işletilecek. Bu, AMD FX-8350 Sekiz Çekirdekli İşlemciye standart bir ubuntu yüklemesidir. Bu ayrıca kodunuzu çalıştırabilmem gerektiği anlamına gelir.

Küçük cevaplar

N = 1..10 için çıktılar 1,1,2,3,5,9,32,56,125,315 olmalıdır

Bu dizi OEIS'te değildir ve bu nedenle kazanan giriş de yeni bir giriş önermektedir.

Şimdiye kadarki girişler

  • n=10 n=11tarafından Vioz tarafından Python
  • n=9C tarafından Tyilo
  • n=12yorum yapan: Legendre in J
  • n=10içinde Tensibai ile R
  • n=14SteelRaven tarafından C ++
  • n=14tarafından RetoKoradi tarafından C ++

@AlexA. Haklısın ve özür diledim. Neyse ki iki problem çok benzer, bu yüzden kodunu kolayca değiştirebilmelidir.

@Vioz'un çözümü 1, 1, 2, 3, 5, 9, 32 ile başlayan bir sıra ile gelir. Yani n = 5 değeri listelediklerinizden farklıdır. Diğer tüm değerler eşleştiğinden, çözüm muhtemelen doğru gibi görünüyor ve bu sadece sorudaki bir yazım hatası mı?
Reto Koradi

@RetoKoradi Teşekkürler. Sabit.

İşte maksimum belirleyicileri olan 10 olası ikili Toeplitz matrisi n = 1..10: ghostbin.com/paste/axkpa
Tyilo

2
Başkalarına yardımcı olabilecek ama 14'ün ötesinde doğrulayamadığım bir gözlem olarak. Üst satırın ilgili araçları ve Toeplitz matrisinin ilk sütunu maksimum belirleyici için her zaman 0.4 <= m <= 0.6'dır.
MickyT

Yanıtlar:


3

Pthreads ile C ++

Bu, makinemde 1 dakikadan kısa bir sürede n = 14 olur. Ancak bu sadece 2 çekirdekli bir dizüstü bilgisayar olduğundan, 8 çekirdekli test makinesinin n = 15'i 2 dakikadan kısa sürede bitirebileceğini umuyorum. Makinemde yaklaşık 4:20 dakika sürüyor.

Gerçekten daha verimli bir şey bulmayı umuyordum. Orada olan var daha verimli bir ikili matris bizim tanımlı hesaplamak için bir yol olarak. Determinant hesaplamada +1 ve -1 terimlerini sayan bir tür dinamik programlama yaklaşımı bulmak istedim. Ama şimdiye kadar pek bir araya gelmedi.

Ödülün süresi dolmak üzereyken, standart kaba kuvvet yaklaşımını uyguladım:

  • Tüm olası Toeplitz matrislerini döngüye sokun.
  • Her bir transpoze edilmiş matris çiftindeki ikisinden birini atlayın. Matris bitmask değerleri ile tanımlandığından, bitmaskinin tersinin bitmaskinin kendisinden daha küçük olduğu tüm değerleri atlayarak bunu yapmak kolaydır.
  • Determinat, bir metin kitabı LR ayrışması ile hesaplanır. Bazı küçük performans ayarlamaları dışında, kolej sayısal yöntemler kitabımdan algoritmaya yaptığım temel gelişme, daha basit bir pivot stratejisi kullanmamdır.
  • Paralelleştirme pthreads ile yapılır. Sadece her bir iş parçacığı tarafından işlenen değerler için düzenli boşluk kullanmak çok kötü yük dengelemesine neden oldu, bu yüzden biraz dalgalanma getirdim.

Bunu Mac OS'de test ettim, ancak daha önce Ubuntu'da benzer bir kod kullandım, bu yüzden bu derleme ve sorunsuz bir şekilde çalışacağını umuyorum:

  1. Kodu, .cppuzantısı olan bir dosyaya kaydedin , örn optim.cpp.
  2. İle derleyin gcc -Ofast optim.cpp -lpthread -lstdc++.
  3. İle çalıştırın time ./a.out 14 8. İlk argüman maksimumdur n. 14 2 dakikadan kısa sürede bitirmeli, ancak 15'i de denemeniz harika olurdu. İkinci argüman iş parçacığı sayısıdır. Makinenin çekirdek sayısı ile aynı değeri kullanmak normalde iyi bir başlangıçtır, ancak bazı varyasyonları denemek zamanları iyileştirebilir.

Kodu oluştururken veya çalıştırırken herhangi bir sorun yaşarsanız bize bildirin.

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

Bir tamsayı matrisinin determinantını sadece tamsayı aritmetiği kullanarak hesaplamanın ilginç bir yolu vardır: bazı sonlu alanlarda LU ayrışması (temelde büyük bir asal mod). Bunun daha hızlı olup olmayacağını bilmiyorum.
lirtosiast

@ThomasKwa Muhtemelen hala O (n ^ 3) olurdu? Kayan nokta hassasiyetinin bir sorun haline geleceği daha büyük matrisler için yararlı olabilir. Gerçekten edebiyat aramadım. Hızlı bir arama yaptım ve Toeplitz matrislerinin belirleyicilerini hesaplama hakkında bir makale buldum. Ama bunu denemek ve uygulamak için zaman ayırmam için çok fazla açık soru vardı.
Reto Koradi

1
@Lembik Bugün daha sonra bir göz atacağım. Dün ilgili diğer zorluklarınız için daha büyük boyutları ele alacak şekilde değiştirdim. Şimdiye kadar n = 30 için en yüksek puanı geçemedim, buluşsal yöntemlerim 5 * 10 ^ 13'ün altında kaldı.
Reto Koradi

1
@Lembik Kod için paste.ubuntu.com/11915546 ve n = 19'a kadar sonuç için paste.ubuntu.com/11915532 adresine bakın .
Reto Koradi

1
@Lembik n = 20'ye kadar olan sonuçlar paste.ubuntu.com/11949738 adresindedir . Şimdi, diyagonalin değerini ve dolaşıcı olup olmadıklarını hızlı bir şekilde görmek için özellikler de dahil olmak üzere tüm bağlı çözümleri listeliyorlar. M = 18,19,20 için maksimumların tamamı sirkülasyon matrisleridir. Lütfen belirleyicileri herhangi bir yerde yayınlamadan önce iki kez kontrol edin.
Reto Koradi

8

J

Güncelleme: Değerlerin yarısından fazlasını aramak için geliştirilmiş kod. Şimdi n=12120 saniye içinde rahat bir şekilde hesaplar (217'den 60'lara kadar).

Yüklü J'nin en son sürümüne ihtiyacınız olacak .

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

Bunu çalıştırın ve iki dakika dolduğunda öldürün. Sonuçlarım (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│
└────┴──┴─────────────┴────┘

Toplam çalışma süresi = 61.83s.


Sadece eğlence için

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

Bu kendi başına yaklaşık 210 saniye sürdü.


1
n = 12Test kullanıcılarına not: yaklaşık 18 GiB bellek gerektirir.
Dennis

Bu çok güzel bir gelişme. Ancak çıktı biraz hatalı. Benim için j64-804 kullanarak iki kez n = 1 çıktı, bu yüzden her zamankinden daha fazla çıktı.

@Lembik Ah doğru. Ben sadece kodu güncelledim; Tekrar koşmayı deneyebilir misin? Teşekkürler! (Ben kadar hesaplamak için ayarladım n=13. İstediğinizi hesaplamak 13için ikinci-son satırda değiştirebilirsiniz.)
Legendre

Tekrar koştum ve hala 12'ye

@Lembik Hmm .. zaman sınırı içinde 12'ye ve bundan bir süre sonra 13'e (yani beklediğim gibi) ya da asla 13'e (yani 12'den sonra program durur) ulaştığını mı söylüyorsunuz?
Legendre

4

Python 2

Bu çok basit bir çözüm ve muhtemelen yarışmayı kazanamayacak. Ama hey, işe yarıyor!

Tam olarak neler olduğuna hızlı bir genel bakış sunacağım.

  1. Öncelikle için mümkün olan her başlangıç ​​satırını oluşturuyorum n. Örneğin, ne zaman n=2bu, her satırın 2n-1 uzunluğunda bir dizi uzunluğu 2 n + 1 üretecektir . Bu şekilde görünecektir: [[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. Daha sonra, bu olası başlangıç ​​satırlarının her biri için, nzamanları döndürür nve uygun matrisi oluşturmak için ilk öğeleri scipydilimliyorum ve maksimum değeri takip ederken determinantı hesaplamak için kullanıyorum . Bunun sonunda, maksimum, artışı n1 oranında yazdırıyorum ve 10 dakika geçene kadar devam ediyorum .

Bunu çalıştırmak için scipy'nin kurulu olması gerekir.

Düzenleme 1: Bunun yerine itertools.product kullanılarak ilk satırların oluşturulma şekli değiştirildi, teşekkürler Sp3000!

Düzenleme 2: Hızı en aza indirmek için olası başlangıç ​​satırlarının kaldırılması.

Edit 3: scipyNasıl detçalıştığı üzerinde daha fazla kontrole sahip olacak şekilde değiştirildi .

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

İşte ev makinemde bazı örnek çıktılar (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

Teşekkür ederim ama korkarım sorunun eski bir versiyonunu cevapladığınızı düşünüyorum. Şimdi Toeplitz matrisleri hakkında ve zaman sınırı 2 dakikadır.

4
Bu sitede çok golf oynayan Python görüyorum, genellikle genel amaçlar için okunabilir bir dil olduğunu unutuyorum.
Alex

Bu muhtemelen önemli ölçüde hızlandırılabilir, çünkü bunun ikili bir matris olması gerçeğinden faydalanmaz.
lirtosiast

@ThomasKwa Dürüst olursam, bundan nasıl yararlanacağım hakkında hiçbir fikrim yok: P
Kade

Numpy belgelerinden alıntı: "Determinant, LAPACK rutin z / dgetrf kullanılarak LU çarpanlarına ayırma yoluyla hesaplanır." Dgetrf'e baktım ve çift kesinlik kullandığını söylüyor; OP'nin GPU'suna bağlı olarak tek hassasiyet daha hızlı olabilir.
lirtosiast

4

C ++

Transpoze edilen matrisler için determinantın değerlendirilmesini önlemek için Paralelleştirme ve basit optimizasyon için OpenMP kullanımı ile Bruteforce.

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

Birisi akıllıca bir fikir

2

C

Şununla derleyin:

$ clang -Ofast 52851.c -o 52851

Şununla çalıştır:

$ ./52851

İçin maksimum determinant çıktısı verebilir n = 1..10Bilgisayarımda ~ 115 saniye içinde verebilirim.

Program sadece olası her boyuttaki Toeplitz boyut matrisini nbelirleyicidir, ancak boyut matrislerinin her belirleyicisi5x5 veya daha küçük hatırlatma kullanılarak önbelleğe alınacak.

İlk başta yanlış bir Toeplitz matrisinin her alt matrisinin de Toeplitz matrisi olacağını varsaydım, bu yüzden sadece her biri için 2^(2n-1)değerleri ezberlemem gerekiyordu . Hatamı fark etmeden önce programı yaptım, bu yüzden bu başvuru sadece o programın bir düzeltmesi.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;
}

Küçüklerin genişlemesini kullanarak determinant hesaplıyormuşsunuz gibi görünüyor; bunun O(n!)karmaşıklığı vardır, bu yüzden farklı bir algoritma kullanarak daha iyi olabilirsiniz.
lirtosiast

@ThomasKwa Daha hızlı algoritmalar olduğunu bilmiyordum, bu yüzden evet bu çözüm oldukça kötü.
Tyilo

Bir matrisin determinantını bulmak için LU Ayrıştırma'yı kullanmak isteyebilirsiniz . O var O(n^3)Gerçi daha hızlı bazı ilginç algoritmalar ile yapılabilir, inan. Burada kullanılan yapıların çoğunun genellikle determinantları gerçekleştirmek için bir çeşit ayrışma varyantı kullandığına inanıyorum.
BrainSteel

@BrainSteel, evet ona baktım, ama O(n^2)cevabımı güncellersem bir algoritma da isteyebilirim .
Tyilo

Sıradan bir Wikipedia araştırmasına göre, bir Toeplitz matrisinin belirleyicisi içinde belirlenebilir O(n^2). Ama sorunun darboğaz arasında arama düşünüyorum O(4^n)birçok 0-1 nile nmatrisleri.
Legendre

2

R,

R'yi ve aşağıdakilerle listelenen paketleri yüklemeniz gerekir: install.packages("package_name")

Bu sürümle makinemde 2 dakikadan az sürmedi (paralel bir değişiklikle denemem gerekiyor)

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

Çağrı ve çıkış:

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

Makinemdeki karşılaştırmalı değerlendirme:

> 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

Bilgi için, 1:11 aralığında, 285 saniye sürer.


1

PARI / GP, n = 11

Bu kaba kuvvettir ama faydalanır det(A^T) = det(A). Sadece aktarımları atlamanın ne kadar kolay olduğunu göstermek için gönderiyorum. En düşük bit, b1sol üst hücreyi tutarken, diğer bitler üst satırın geri kalanını tutar. b2sol sütunun geri kalanını tutar. Biz sadece uygularız 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);
  )
}

Bilgi işlem Toeplitz belirleyicileri ile ilgili olarak O(n^2): Sınırlı araştırmamda, algoritmaların çalışması için tüm önde gelen ana reşit olmayanların sıfır olması gerektiği bir zorunlulukla karşılaştım, bu da bu görev için büyük bir engel. Bu konuda benden daha fazla bilgi sahibi olursanız bana işaretçi olmaktan çekinmeyin.


Bu makaleyi gördün mü? scienpress.com/upload/JAMB/Vol%201_1_4.pdf . Karmaşıklığın ne olduğu bana açık değildi. N = 5 örneği için oldukça fazla terim var gibi görünüyordu.
Reto Koradi

@RetoKoradi Evet gördüm. Karmaşıklığın, örneğin e_{k+1}bileşen sayısının 4 katına sahip olduğu düşünüldüğünde, polinom değildir e_k. Makalede birçok eksiklik var. Tersinir bir matris, tüm önde gelen ana reşit olmayanların sıfır olmaması durumunda LU ayrışmasına sahiptir. (Paydalara dikkat edin, örneğin a_0- örtük olarak sıfırdan farklı oldukları garanti edilir.) Benzersizlik, L'nin birim üçgen olması ile sağlanır. Yazar ayrıca sayısal kararlılıktan da bahsetmedi. Bağlantının kullanılamaması durumunda makale Hsuan-Chu Li (2011) tarafından "Toeplitz Matrislerinin Belirleyicilerinin Hesaplanması Üzerine" dir.
Mitch Schwartz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.