Hadamard问题的优化版本


11

首先,一些定义。

Hadamard矩阵是方阵,其条目是+1或-1,并且其行是相互正交的。所述哈达玛猜想提出的顺序4k的Hadamard矩阵存在每一个正整数k。

循环矩阵是一类特殊的矩阵,其中每一行向量是一个旋转元件的相对前述行向量权。那就是矩阵是由它的第一行定义的。

已知的是,除了4×4的矩阵,有没有循环Hadamard矩阵

具有m行和n> = m列的矩阵是局部循环,如果是一些循环矩阵的第一m行。

任务

对于从2开始的每个偶数n,输出具有+ -1项和n列的最大部分循环矩阵的大小,该矩阵的所有行都相互正交。

得分了

您的分数是最高的n,因此k <= n,没有任何人比您发布的正确答案更高。显然,如果您拥有所有最佳答案,那么您将获得n您发布的最高分数。但是,即使您的答案不是最佳答案,如果没有其他人能打败它,您仍然可以获得分数。

语言和图书馆

您可以使用任何喜欢的语言和库。在可行的情况下,能够运行您的代码将是一件好事,因此,请尽可能提供有关如何在Linux中运行/编译代码的完整说明。

领先的作品

  • Mitch Schwartz在Python中撰写的64

Answers:


7

Python 2

餐桌最高n = 64,经验证的最佳蛮力最高n = 32

 4  4 0001
 8  4 00010001
12  6 000001010011
16  8 0000010011101011
20 10 00010001011110011010
24 12 000101001000111110110111
28 14 0001011000010011101011111011
32 14 00001101000111011101101011110010
36 18 001000101001000111110011010110111000
40 20 0010101110001101101111110100011100100100
44 18 00010000011100100011110110110101011101101111
48 24 001011011001010111111001110000100110101000000110
52 26 0011010111000100111011011111001010001110100001001000
56 28 00100111111101010110001100001101100000001010100111001011
60 30 000001101101100011100101011101111110010010111100011010100010
64 32 0001100011110101111111010010011011100111000010101000001011011001

在哪里0代表-1。如果n不能被4整除,m = 1则为最佳。使用此代码(或代码的较小变化)生成,但针对更高的代码需要进行更多的尝试n

from random import *

seed(10)

trials=10000

def calcm(x,n):
    m=1
    y=x
    while 1:
        y=((y&1)<<(n-1))|(y>>1)
        if bin(x^y).count('1')!=n/2:
            return m
        m+=1

def hillclimb(x,n,ns):
    bestm=calcm(x,n)

    while 1:
        cands=[]

        for pos in ns:
            xx=x^(1<<pos)
            m=calcm(xx,n)

            if m>bestm:
                bestm=m
                cands=[xx]
            elif cands and m==bestm:
                cands+=[xx]

        if not cands:
            break

        x=choice(cands)

    return x,bestm

def approx(n):
    if n<10: return brute(n)

    bestm=1
    bestx=0

    for trial in xrange(1,trials+1):
        if not trial&16383:
            print bestm,bin((1<<n)|bestx)[3:]

        if not trial&1:
            x=randint(0,(1<<(n/2-2))-1)
            x=(x<<(n/2)) | (((1<<(n/2))-1)^x)
            ns=range(n/2-2)

            if not trial&7:
                adj=randint(1,5)
                x^=((1<<adj)-1)<<randint(0,n/2-adj)
        else:
            x=randint(0,(1<<(n-2))-1)
            ns=range(n-2)

        x,m=hillclimb(x,n,ns)

        if m>bestm:
            bestm=m
            bestx=x

    return bestm,bestx

def brute(n):
    bestm=1
    bestx=0

    for x in xrange(1<<(n-2)):
        m=calcm(x,n)
        if m>bestm:
            bestm=m
            bestx=x

    return bestm,bestx

for n in xrange(4,101,4):
    m,x=approx(n)
    print n,m,bin((1<<n)|x)[3:]

该方法是利用爬坡的简单随机搜索,利用了注意到小的模式n。模式是为了获得最佳效果m,第一行的后半部分与前半部分的(按位)取反通常具有较小的编辑距离。上面代码的结果不错,n但是在蛮力变得不可行之后不久就开始恶化。我很高兴看到更好的方法。

一些观察:

  • n为奇数时,这m = 1是最佳选择,因为奇数个数的一和负数的总数不能为零。(正交表示点积为零。)
  • n = 4k + 2m = 1是最理想的,因为为了m >= 2我们需要有确切n/2签署之间的逆转{(a1,a2), (a2,a3), ... (a{n-1},an), (an,a1)},以及奇数符号颠倒的将暗示a1 = -a1
  • 的两行中的点积ij在一个循环矩阵由下式确定abs(i-j)。例如,如果row1 . row2 = 0then row4 . row5 = 0。这是因为点积的成对元素是相同的,只是旋转而已。
  • 因此,为了检查相互正交性,我们只需要对照第一行检查连续的行。
  • 如果我们用0代替-1,将其表示为二进制字符串,则可以通过按位异或并将popcount与进行比较来检查两行的正交性n/2
  • 我们可以任意地固定第一行的前两个元素,因为(1)否定矩阵不会影响点积是否等于零,并且(2)我们知道至少必须有两个相邻的元素具有相同的符号和两个相邻元素的符号不同,因此我们可以旋转以将所需的对放在开头。
  • 一个解决方案(n0, m0)将自动(反复)将第一行连接到其自身,从而(k * n0, m0)提供任意的解决方案k > 1。结果是,我们可以很容易地获得m = 4任何n被4整除。

很自然地猜想这n/2mwhen 的严格上限n > 4,但是我不知道如何证明这一点。


非常有趣的是,没有16行32列的解决方案。你知道为什么吗

@Lembik如果我有一个主意,我会在答案中写出来。
米奇·施瓦茨
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.