找到每个尺寸Toeplitz矩阵的最大行列式


14

对于固定的n,请考虑条目为0或1 的n×n Toeplitz矩阵。目的是在所有此类Toeplitz矩阵上找到最大行列式。

任务

对于n从1到更高的每个,输出在所有n×n Toeplitz矩阵上的最大行列式,其条目为0或1。每个输出n应该有一个最大行列式的输出,并且有一个达到它的示例矩阵。

得分了

您的分数是n您的代码在我的计算机上2分钟内获得的最高分。为了澄清一点,您的代码总共可以运行2分钟,而不是每个2分钟n

抢领带

如果两个条目获得相同的n分数,那么获胜的条目将是n在我的机器上最短时间内获得最高得分的条目。如果两个最佳作品在此标准上也相等,那么获胜者将是第一个提交的答案。

语言和图书馆

您可以使用任何喜欢的免费语言和库。我必须能够运行您的代码,因此请尽可能提供有关如何在Linux中运行/编译代码的完整说明。

我的机器时间将在我的机器上运行。这是在AMD FX-8350八核处理器上的标准ubuntu安装。这也意味着我需要能够运行您的代码。

小答案

对于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 in 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 2015年

@RetoKoradi谢谢。固定。

以下是10个可能的最大决定因素的二进制Toeplitz矩阵n = 1..10ghostbin.com/paste/axkpa
Tyilo

2
作为一种可能对其他人有所帮助的观察结果,但我无法超出14进行验证。对于最大行列式来说,Toeplitz矩阵的第一行和第一列的相应平均值始终为0.4 <= m <= 0.6。
MickyT

Answers:


3

带有pthread的C ++

在我的机器上,不到1分钟的时间便达到了n = 14。但是,由于那只是2核笔记本电脑,我希望8核测试机能够在2分钟内完成n = 15。我的机器大约需要4:20分钟。

我真的很想提出一个更有效的方法。必须一种方法可以更有效地计算二进制矩阵的确定性。我想提出一种动态编程方法,该方法在行列式计算中计算+1和-1项。但是到目前为止,它还没有完全融合在一起。

由于赏金即将到期,因此我实施了标准的暴力手段:

  • 遍历所有可能的Toeplitz矩阵。
  • 跳过每个转置矩阵对中的两个之一。由于矩阵是由位掩码值描述的,因此通过跳过位掩码的倒数小于位掩码本身的所有值,可以轻松做到这一点。
  • 通过教科书LR分解计算确定值。除了一些小的性能调整外,我从大学数值方法书中对该算法所做的主要改进是,我使用了一种更简单的枢轴策略。
  • 并行化是通过pthreads完成的。仅对每个线程处理的值使用常规间距会导致非常差的负载平衡,因此我引入了一些麻烦。

我在Mac OS上进行了测试,但之前在Ubuntu上使用过类似的代码,因此我希望它可以编译并顺利运行:

  1. 使用以下命令将代码保存到文件中 .cpp扩展名,例如optim.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 2015年

@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 2015年

8

Ĵ

更新:改进的代码可搜索一半以上的值。现在可以n=12在120秒内轻松计算(从217s降至60s)。

您将需要安装最新版本的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-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.83s。


只是为了好玩

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

它本身花费了大约210秒。


1
测试人员注意:n = 12大约需要18 GiB的内存。
丹尼斯

这是一个非常不错的改进。但是,输出略有错误。对我来说,使用j64-804会输出n = 1两次,因此它永远被1淘汰。

@Lembik啊是的。我刚刚更新了代码;你可以再试一次吗?谢谢!(我将其设置为最多计算n=13。您可以更改13倒数第二行中的值以使其计算您想要的任何值。)
Legendre

我再次运行它,它仍然到达12

@Lembik Hmm ..您是说它在时限内达到12,然后在那之后的某个时间达到13(这是我所期望的),还是从未达到13(即程序在12点后停止)?
勒让

4

Python 2

这是一个非常简单的解决方案,可能不会赢得比赛。但是,嘿!

我将简要概述正在发生的事情。

  1. 我首先为生成所有可能的起始行n。例如,当时n=2,将生成一个数组长度2 n + 1,其中每行的长度为2 n -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:感谢Sp3000,更改了通过使用itertools.product构建初始行的方式!

编辑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,以至于我通常忘记了它实际上是一种可读的语言。
Alex A.

这可能会大大加快,因为它没有利用它是二进制矩阵这一事实。
lirtosiast,2015年

@ThomasKwa如果我说老实话,我不知道如何利用这一点:P
Kade 2015年

引用numpy文档:“行列式使用LAPACK例程z / dgetrf通过LU分解计算。” 我看着dgetrf,它说它使用双精度。取决于OP的GPU的单精度可能会更快。
lirtosiast 2015年

4

C ++

Bruteforce使用OpenMP进行并行化和简单优化,以避免评估转置矩阵的行列式。

$ 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

C

编译:

$ clang -Ofast 52851.c -o 52851

运行:

$ ./52851

可以n = 1..10在我的计算机上在约115秒内输出最大行列式。

该程序只是获得行列式的每个可能的二进制Toeplitz大小n的矩阵,但是5x5将使用备忘录来缓存每个大小或更小的矩阵的行列式。

最初,我错误地假设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 2015年

@ThomasKwa我不知道有更快的算法,所以是的,这个解决方案非常糟糕。
蒂洛2015年

您可能需要研究使用LU分解来查找矩阵的行列式。这是O(n^3),我认为,尽管可以做出一些有趣的算法快。我相信这里使用的大多数内置函数通常使用分解的变体来执行行列式。
BrainSteel

@BrainSteel,是的,我看了一下,但是O(n^2)如果我更新自己的答案,不妨去寻找一种算法。
蒂洛2015年

根据偶然的Wikipedia搜索,可以在中确定Toeplitz矩阵的行列式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: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);
  )
}

关于O(n^2)及时计算Toeplitz决定因素:在我有限的研究中,我一直要求所有领先的主要未成年人必须不为零才能使算法起作用,这是此任务的主要障碍。如果您比我了解更多,请随时给我指点。


你看到这篇论文了吗?scienpress.com/upload/JAMB/Vol%201_1_4.pdf。我不清楚复杂性是什么。对于n = 5的示例,似乎有很多术语。
Reto Koradi

@RetoKoradi是的,我看到了。考虑到例如e_{k+1}具有的分量数是的4倍,看来复杂度不是多项式e_k。本文有许多遗漏之处。一个可逆矩阵具有LU分解,前提是所有主要的主要次要对象都不为零。(注意分母,例如a_0-隐式地保证它们不为零。)唯一性来自于L是单位三角形。作者也没有提及数值稳定性。万一链接不可用,本文为Hsuan-Chu Li(2011)撰写的“论计算Toeplitz矩阵的行列式”。
米奇·施瓦兹
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.