Python 2
Table jusqu'à n = 64
, vérifié optimal avec force brute jusqu'à 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
où 0
représente -1
. Si n
n'est pas divisible par 4, alors m = 1
est optimal. Généré à l'aide de ce code (ou de petites variantes de celui-ci) mais avec plus d'essais pour plus 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:]
L'approche est une simple recherche aléatoire avec escalade, profitant d'un schéma remarqué pour les petits n
. Le motif est que pour une optimisation m
, la seconde moitié de la première ligne a souvent une petite distance d'édition par rapport à la négation (au niveau du bit) de la première moitié. Les résultats pour le code ci-dessus sont bons pour les petits n
mais commencent à se détériorer peu de temps après que la force brute soit devenue impossible; Je serais heureux de voir une meilleure approche.
Quelques observations:
- Quand
n
est impair, m = 1
est optimal car un nombre impair de uns et de négatifs ne peut pas s'additionner à zéro. (Orthogonal signifie que le produit scalaire est nul.)
- Quand
n = 4k + 2
, m = 1
est optimal car pour que m >= 2
nous ayons besoin d'avoir exactement des n/2
inversions de signe parmi {(a1,a2), (a2,a3), ... (a{n-1},an), (an,a1)}
, et un nombre impair d'inversion de signe impliquerait a1 = -a1
.
- Le produit scalaire de deux rangées
i
et j
dans une matrice circulante est déterminé par abs(i-j)
. Par exemple, si row1 . row2 = 0
alors row4 . row5 = 0
. C'est parce que les paires d'éléments pour le produit scalaire sont les mêmes, juste tournées.
- Par conséquent, pour vérifier l'orthogonalité mutuelle, il suffit de comparer les lignes successives à la première ligne.
- Si nous représentons une ligne comme une chaîne binaire avec
0
à la place de -1
, nous pouvons vérifier l'orthogonalité de deux lignes en prenant xor au niveau du bit et en comparant le popcount avec n/2
.
- Nous pouvons fixer arbitrairement les deux premiers éléments de la première ligne, car (1) la négation d'une matrice n'affecte pas si les produits scalaires sont égaux à zéro, et (2) nous savons qu'il doit y avoir au moins deux éléments adjacents avec le même signe et deux éléments adjacents avec signe différent, afin que nous puissions tourner pour placer la paire souhaitée au début.
- Une solution
(n0, m0)
donnera automatiquement des solutions (k * n0, m0)
arbitraires k > 1
, en concaténant (à plusieurs reprises) la première ligne à elle-même. Une conséquence est que l'on peut facilement obtenir m = 4
pour tout n
divisible par 4.
Il est naturel de conjecturer que n/2
c'est une limite supérieure stricte pour m
quand n > 4
, mais je ne sais pas comment cela serait prouvé.