各サイズのテプリッツ行列の最大行列式を見つける


14

固定nの場合、0または1のエントリを持つn行n列のテプリッツ行列を考えます。目的は、このようなテプリッツ行列すべての最大行列式を見つけることです。

仕事

それぞれn1から上に、0または1のエントリを持つすべてのn行n列のテプリッツ行列の最大行列式を出力します。n最大行列式とそれに到達する行列の例が1つあります。

スコア

スコアは、n私のコンピューター上でコードが2分以内に到達する最大のスコアです。少し明確にするために、コードは合計で2分間実行できますが、これはあたり2分ではありませんn

タイ・ブレーカー

2つのエントリが同じnスコアを獲得した場合、勝者のエントリはn、マシン上で最短時間で最高のエントリになります。この基準でも2つのベストエントリが等しい場合、勝者は最初に送信された回答になります。

言語とライブラリ

自由に利用できる任意の言語とライブラリを使用できます。私はあなたのコードを実行できなければならないので、可能な限りLinuxでコードを実行/コンパイルする方法の完全な説明を含めてください。

私のマシンタイミングは私のマシンで実行されます。これは、AMD FX-8350 8コアプロセッサへの標準のUbuntuインストールです。これは、コードを実行できる必要があることも意味します。

小さな答え

n = 1..10の場合、出力は1,1,2,3,5,9,32,56,125,315になります

このシーケンスはOEISにはないため、受賞エントリはそこに新しいエントリを提案することもできます。

これまでのエントリー

  • n=10 n=11Pythonの Viozによる
  • n=9ティロによるC
  • n=12ルジャンドルのJ
  • n=10Rの Tensibaiによって
  • n=14C ++の SteelRavenによる
  • n=14C ++の RetoKoradiによる

@AlexA。あなたは正しいです、私は謝罪しました。幸いなことに、2つの問題は非常によく似ているため、コードを簡単に変更できるはずです。

@Viozによる解決策は、1、1、2、3、5、9、32で始まるシーケンスになります。したがって、n = 5の値は、リストしたものとは異なります。他のすべての値が一致するため、解はおそらく正しいように見えますが、これは質問のタイプミスですか?
レトコラディ

@RetoKoradiありがとうございます。修繕。

以下に最大行列式を持つ10の可能なバイナリテプリッツ行列を示しn = 1..10ます。ghostbin.com
paste

2
他の人を助けるかもしれないが、14を超えて検証できない観測として、テプリッツ行列の一番上の行と最初の列のそれぞれの平均は、最大行列式に対して常に0.4 <= m <= 0.6であるように見えます。
MickyT

回答:


3

pthreadを使用したC ++

これは、私のマシンでは1分弱でn = 14になります。しかし、それは単なる2コアのラップトップであるため、8コアのテストマシンが2分以内にn = 15を終了できることを願っています。私のマシンでは約4:20分かかります。

もっと効率的なものを思いつきたいと思っていました。そこていました、より効率的にバイナリ行列の確定を計算するための方法であると。行列式の計算で+1と-1の項を数える、ある種の動的プログラミングアプローチを思いつきました。しかし、これまでのところ、まだ完全には一致していません。

報奨金はもうすぐ切れるので、標準的なブルートフォースアプローチを実装しました。

  • 可能なすべてのテプリッツ行列をループします。
  • 各転置行列ペアの2つのうちの1つをスキップします。マトリックスはビットマスク値で記述されるため、ビットマスクの逆がビットマスク自体よりも小さいすべての値をスキップすることにより、これを簡単に行うことができます。
  • 確定値は、テキストブックLR分解で計算されます。いくつかのマイナーなパフォーマンスチューニングを除き、大学の数値手法の本からアルゴリズムに加えた主な改善点は、より単純なピボット戦略を使用することです。
  • 並列化はpthreadを使用して行われます。各スレッドによって処理される値に通常の間隔を使用すると、負荷分散が非常に悪くなり、スウィズルが発生しました。

私はこれをMac OSでテストしましたが、以前Ubuntuで同様のコードを使用したため、これが問題なくコンパイルおよび実行されることを願っています。

  1. コードを.cpp拡張子付きのファイルに保存します(例:)optim.cpp
  2. でコンパイルしgcc -Ofast optim.cpp -lpthread -lstdc++ます。
  3. で実行しtime ./a.out 14 8ます。最初の引数は最大値nです。14は確実に2分以内に終了するはずですが、15を試してみるのもいいでしょう。2番目の引数は、スレッドの数です。マシンのコアの数と同じ値を使用することは通常良いスタートですが、いくつかのバリエーションを試してみると時間を改善できる可能性があります。

コードの構築または実行に問題がある場合はお知らせください。

#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分解(基本的には大きな素数を変更します)。これが速いかどうかはわかりません。
リスト管理者

@ThomasKwaそれはおそらくまだO(n ^ 3)でしょうか?そうしないと、浮動小数点の精度が問題になるような大きなマトリックスに役立ちます。私は本当に文学を探しませんでした。さて、私は簡単な検索を行い、テプリッツ行列の行列式の計算に関する論文を見つけました。しかし、未解決の質問が多すぎて、試して実装する時間を割くことができませんでした。
レトコラディ

1
@Lembik今日は後で試してみます。昨日、他の関連するチャレンジの大きなサイズを処理するように変更しました。これまでのところ、n = 30で最高のスコアを打つことができませんでした。私のヒューリスティックは5 * 10 ^ 13を下回っています。
レトコラディ

1
@Lembik参照のpaste.ubuntu.com/11915546コードとのためpaste.ubuntu.com/11915532アップN = 19の結果を得るために。
レトコラディ

1
@Lembik n = 20までの結果はpaste.ubuntu.com/11949738にあります。対角線の値とそれらが循環しているかどうかをすばやく確認するための属性を含む、関連付けられたすべてのソリューションをリストします。m = 18,19,20の最大値はすべて循環行列です。任意の場所に公開する前に、行列式を再確認してください。
レトコラディ

8

J

更新:半分以上の値を検索するようにコードを改善しました。n=12120秒以内に快適に計算できるようになりました(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''

これを実行し、2分が経過したら殺します。私の結果(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│
└────┴──┴─────────────┴────┘

合計実行時間= 61.83秒。


ただの楽しみのために

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

これには約210秒かかりました。


1
テスターへの注意:n = 12約18 GiBのメモリが必要です。
デニス

これは非常に素晴らしい改善です。ただし、出力には少しバグがあります。j64-804を使用している私にとっては、n = 1を2回出力するので、ずっと1ずつ出力されます。

@Lembikあ、そうです。コードを更新しました。もう一度実行してみてください。ありがとう!(最大で計算するように設定しましたn=1313最後から2番目の行のを変更して、任意に計算できるようにします。)
ルジャンドル

私はそれを再度実行し、それでもまだ12に

@Lembik Hmm ..制限時間内に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

ありがとうございますが、あなたは私が恐れている質問の古いバージョンに答えたと思います。現在はテプリッツ行列についてであり、制限時間は2分です。

4
このサイトにはたくさんのPythonがありますが、一般的な目的のために実際に読みやすい言語であることをよく忘れます。
アレックスA.

これはおそらくバイナリマトリックスであるという事実を利用しないため、大幅に高速化される可能性があります。
リトシアスト

@ThomasKwa正直なところ、私はそれを利用する方法がわかりません:P
Kade

numpyのドキュメントからの引用:「行列式は、LAPACKルーチンz / dgetrfを使用してLU分解によって計算されます。」dgetrfを見たところ、倍精度を使用していると書かれています。OPのGPUに応じて、単精度がより高速になる可能性があります。
リトシアスト

4

C ++

転置行列の行列式の評価を回避するための並列化および単純な最適化にOpenMPを使用する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);
  }
}

誰かが巧妙なアイデアを

2

C

コンパイル:

$ clang -Ofast 52851.c -o 52851

で実行:

$ ./52851

の最大行列式を出力できます n = 1..10コンピューターで 115秒間で。

プログラムは、サイズの可能なすべてのバイナリテプリッツ行列の行列式を取得していますがn、サイズの行列のすべての行列式を取得しています5x5以下メモ化を使用してキャッシュされます。

最初は、テプリッツ行列のすべてのサブ行列もテプリッツ行列であると誤って想定していたため、eachの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!)複雑さが伴うため、別のアルゴリズムを使用する方がよい場合があります。
リトシアスト

@ThomasKwaより高速なアルゴリズムがあることは知らなかったので、このソリューションはかなり悪いです。
ティロ

LU Decompositionを使用して、マトリックスの行列式を見つけることをお勧めします。それはだO(n^3)より速く、いくつかの興味深いのアルゴリズムで行うことができますが、私は信じています、。ここで使用されているほとんどの組み込み関数は、一般に分解のバリアントを使用して行列式を実行すると考えています。
BrainSteel

@BrainSteel、ええ、私はそれを見ましたがO(n^2)、答えを更新しているなら、アルゴリズムに行くかもしれません。
ティロ

ウィキペディアのカジュアルな検索によると、テプリッツ行列の行列式はで決定できますO(n^2)。しかし、私は、問題のボトルネックが間探していると思うO(4^n)多くの0-1 nnの行列。
ルジャンドル

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:1の範囲の場合、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);
  )
}

O(n^2)時間内にテプリッツの行列式を計算することに関して:私の限られた研究では、アルゴリズムが機能するためにすべての主要な主要な未成年者がゼロ以外でなければならないという要件に直面し続けました。これはこのタスクの大きな障害です。あなたが私よりもこれについてもっと知っているなら、私にポインタを与えてください。


この論文を見ましたか?scienpress.com/upload/JAMB/Vol%201_1_4.pdf。複雑さについては明確ではありませんでした。n = 5の例には非常に多くの用語があるように見えました。
レトコラディ

@RetoKoradiはい、見ました。たとえばe_{k+1}、の4倍の成分数を持っていることを考えると、複雑さは多項式ではないようe_kです。論文には多くの記載漏れがあります。可逆行列は、すべての主要なプリンシパルマイナーがゼロ以外である場合、LU分解を持ちます。(分母に注意してください。たとえば、a_0暗黙的にゼロでないことが保証されています。)一意性は、Lが単位三角形であることから生じます。著者はまた、数値の安定性についても言及していません。リンクが利用できなくなった場合の論文は、Hsuan-Chu Li(2011)による「Toeplitz行列の決定要因の計算について」です。
ミッチシュワルツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.