เวอร์ชันการปรับให้เหมาะสมที่สุดของปัญหา Hadamard


11

ก่อนคำจำกัดความบางอย่าง

Hadamard เมทริกซ์เป็นเมทริกซ์ตารางที่มีรายการที่มีทั้ง +1 หรือ -1 และมีแถวฉากร่วมกัน การคาดคะเน Hadamardเสนอว่าเมทริกซ์ Hadamard ของการสั่งซื้อ 4k มีอยู่สำหรับทุกจำนวนเต็มบวก k

เมทริกซ์ circulantเป็นเมทริกซ์พิเศษที่แต่ละเวกเตอร์แถวถูกหมุนหนึ่งองค์ประกอบทางด้านขวาเทียบกับเวกเตอร์แถวก่อนหน้า นั่นคือเมทริกซ์ถูกกำหนดโดยแถวแรก

มันเป็นที่รู้จักกันว่ายกเว้น 4 4 การฝึกอบรมมีไม่มีการฝึกอบรม Hadamard circulant

เมทริกซ์ที่มีแถว m และคอลัมน์ n> = m เป็นcirculant บางส่วนถ้าเป็นแถว m แรกของเมทริกซ์ circulant บางตัว

งาน

สำหรับแต่ละเลขจำนวนเต็ม n ที่เริ่มต้นที่ 2 เอาท์พุทขนาดของเมทริกซ์ circulant บางส่วนที่ใหญ่ที่สุดด้วย + -1 รายการและคอลัมน์ n ที่มีคุณสมบัติที่ทุกแถวของมันตั้งฉากกัน

คะแนน

คะแนนของคุณนั้นสูงที่สุดnสำหรับทุกคนk <= nไม่มีใครโพสต์คำตอบที่ถูกต้องสูงกว่าคุณ เห็นได้ชัดว่าถ้าคุณมีคำตอบที่ดีที่สุดแล้วคุณจะได้รับคะแนนสูงสุดสำหรับการnโพสต์ อย่างไรก็ตามแม้ว่าคำตอบของคุณจะไม่เหมาะสมคุณก็ยังสามารถได้คะแนนถ้าไม่มีใครสามารถเอาชนะได้

ภาษาและห้องสมุด

คุณสามารถใช้ภาษาและไลบรารีใด ๆ ที่คุณต้องการ หากเป็นไปได้จะเป็นการดีที่จะสามารถเรียกใช้รหัสของคุณได้ดังนั้นโปรดระบุคำอธิบายโดยละเอียดเกี่ยวกับวิธีเรียกใช้ / รวบรวมรหัสของคุณใน Linux หากเป็นไปได้

รายการชั้นนำ

  • 64โดย Mitch Schwartz ในPython

คำตอบ:


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จะดีที่สุดเพราะจำนวนคี่และจำนวนลบไม่สามารถรวมกันเป็นศูนย์ได้ (orthogonal หมายถึง dot product เป็นศูนย์)
  • เมื่อn = 4k + 2, m = 1จะดีที่สุดเพราะในการสั่งซื้อสำหรับm >= 2เราจำเป็นต้องได้ว่าn/2ลงนามในการพลิกผันในหมู่และเลขคี่ของการพลิกผันเข้าสู่ระบบจะบ่งบอก{(a1,a2), (a2,a3), ... (a{n-1},an), (an,a1)}a1 = -a1
  • ผลิตภัณฑ์ dot สองแถวiและjในเมทริกซ์ circulant abs(i-j)จะถูกกำหนดโดย ตัวอย่างเช่นถ้าแล้วrow1 . row2 = 0 row4 . row5 = 0นี่เป็นเพราะองค์ประกอบคู่สำหรับผลิตภัณฑ์ดอทเหมือนกันเพียงหมุน
  • ดังนั้นสำหรับการตรวจสอบ orthogonality ร่วมกันเราจะต้องตรวจสอบแถวต่อเนื่องกับแถวแรก
  • ถ้าเราเป็นตัวแทนแถวเป็นสตริงไบนารีที่มี0ในสถานที่ของ-1เราสามารถตรวจสอบการตั้งฉากที่สองแถวโดยการบิต xor และเปรียบเทียบ popcount n/2ด้วย
  • เราสามารถแก้ไขสององค์ประกอบแรกของแถวแรกโดยพลการเนื่องจาก (1) การลบเมทริกซ์จะไม่ส่งผลต่อว่าจุดของผลิตภัณฑ์เท่ากับศูนย์และ (2) เรารู้ว่าต้องมีองค์ประกอบที่อยู่ติดกันอย่างน้อยสองรายการที่มีเครื่องหมายเดียวกัน องค์ประกอบที่อยู่ติดกันมีเครื่องหมายที่แตกต่างกันดังนั้นเราสามารถหมุนเพื่อวางคู่ที่ต้องการในตอนต้น
  • การแก้ปัญหา(n0, m0)โดยอัตโนมัติจะให้โซลูชั่น(k * n0, m0)สำหรับโดยพลการk > 1โดย (ซ้ำ) เชื่อมต่อแถวแรกกับตัวเอง ผลที่ตามมาคือเราสามารถหาได้ง่ายm = 4สำหรับการnหารใด ๆด้วย 4

มันเป็นเรื่องธรรมดาที่จะคาดเดาว่าn/2มันจะเป็นขอบเขตที่แน่นแต่mเมื่อใดn > 4แต่ฉันไม่รู้ว่ามันจะพิสูจน์ได้อย่างไร


มันน่าสนใจมากที่ไม่มีวิธีแก้ปัญหาด้วย 16 แถวและ 32 คอลัมน์ คุณมีความคิดใด ๆ ว่าทำไม?

@ Lembik ถ้าฉันมีความคิดฉันจะเขียนมันในคำตอบ
Mitch Schwartz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.