Codegolf Hafnian


22

ความท้าทายคือการเขียน codegolf สำหรับHafnian ของเมทริกซ์ Hafnian ของเมทริกซ์2n-by- 2nสมมาตรAหมายถึง:

ป้อนคำอธิบายรูปภาพที่นี่

นี่ S 2nหมายถึงชุดของพีชคณิตทั้งหมดของจำนวนเต็มจาก1การที่เป็น2n[1, 2n]

ลิงค์วิกิพีเดียพูดถึงการฝึกหัด adjacency แต่รหัสของคุณควรใช้กับเมทริกซ์อินพุตสมมาตรที่มีมูลค่าจริง ๆ

สำหรับผู้ที่สนใจในแอปพลิเคชันของHafnianลิงก์mathoverflow จะกล่าวถึงเพิ่มเติม

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

อินพุตเมทริกซ์เป็นรูปสี่เหลี่ยมจัตุรัสเสมอและจะมีค่าสูงสุด 16 คูณ 16 ไม่จำเป็นต้องจัดการเมทริกซ์ว่างเปล่าหรือเมทริกซ์ของมิติคี่

การดำเนินการอ้างอิง

นี่คือตัวอย่างโค้ดไพ ธ อนจาก Mr. Xcoder

from itertools import permutations
from math import factorial

def hafnian(matrix):
    my_sum = 0
    n = len(matrix) // 2
    for sigma in permutations(range(n*2)):
        prod = 1
        for j in range(n):
            prod *= matrix[sigma[2*j]][sigma[2*j+1]]
        my_sum += prod
    return my_sum / (factorial(n) * 2 ** n)


print(hafnian([[0, 4.5], [4.5, 0]]))
4.5
print(hafnian([[0, 4.7, 4.6, 4.5], [4.7, 0, 2.1, 0.4], [4.6, 2.1, 0, 1.2], [4.5, 0.4, 1.2, 0]])
16.93
print(hafnian([[1.3, 4.1, 1.2, 0.0, 0.9, 4.4], [4.1, 4.2, 2.7, 1.2, 0.4, 1.7], [1.2, 2.7, 4.9, 4.7, 4.0, 3.7], [0.0, 1.2, 4.7, 2.2, 3.3, 1.8], [0.9, 0.4, 4.0, 3.3, 0.5, 4.4], [4.4, 1.7, 3.7, 1.8, 4.4, 3.2]])
262.458

หน้า wiki ได้รับการอัปเดตโดย ShreevatsaR ในวันนี้ (2 มีนาคม 2018) เพื่อรวมวิธีอื่นในการคำนวณ Hafnian มันน่าสนใจมากที่ได้เห็นนักกอล์ฟคนนี้


5
ฉันคิดว่ามันจะย่อยง่ายขึ้นด้วยคำอธิบายที่ไม่เป็นทางการของชาวแฮฟเนียม เหมือนกันให้นำชุดย่อยของรายการเมทริกซ์ทั้งหมดที่ดัชนี n แถวและดัชนีคอลัมน์ n มารวมกันเป็นพาร์ติชั่น 1..2n นำผลงานของแต่ละรายการมาเพิ่มและขยายผลรวม
xnor

คำตอบ:


9

R , 150 142 127 119 ไบต์

function(A,N=nrow(A),k=1:(N/2)*2)sum(apply(gtools::permutations(N,N),1,function(r)prod(A[cbind(r[k-1],r[k])])))/prod(k)

ลองออนไลน์!

ใช้เคล็ดลับแบบเดียวกันกับที่ฉันค้นพบว่าการตอบคำถามนี้ลงดัชนีเมทริกซ์Pและ@Vloแนะนำวิธีการลบforลูปสำหรับ -6 ไบต์โดยสิ้นเชิง!

matrix(c(values,separated,by,commas,going,across,rows),nrow=2n,ncol=2n,byrow=T)เพื่อสร้างกรณีทดสอบใหม่ที่คุณสามารถทำได้

คำอธิบาย: (รหัสเหมือนกันมันใช้การapplyแทนการforวนซ้ำ แต่ตรรกะนั้นเหมือนกัน)

function(A){
N <- nrow(A)                   #N = 2*n
k <- 1:(N/2) * 2               #k = c(2,4,...,N) -- aka 2*j in the formula
P <- gtools::permutations(N,N) #all N-length permutations of 1:N
for(i in 1:nrow(P))
 F <- F + prod(A[cbind(P[i,k-1],P[i,k])]) # takes the product of all A_sigma(2j-1)sigma(2j) for fixed i and adds it to F (initialized to 0)
F / prod(k)                    #return value; prod(k) == n! * 2^n
}


การสมัครมีราคาถูกลง 2 ไบต์ซึ่งช่วยให้สามารถบันทึกได้อีก 4 ไบต์โดยการยัดเยียดบรรทัดอื่น ๆ เข้าด้วยกัน tio.run/##PY6xDoIwEIZ3nsLxzpxiS4ymkYEXYHIjDFDEEKBtSokS47PX4sDw5/ ภาษามันน่าสนใจทีเดียวที่ฐาน R ขาดฟังก์ชั่นการเรียงสับเปลี่ยนสำหรับภาษาทางสถิติ
Vlo

@Vlo ดีมาก! เราสามารถย้ายNและkเข้าสู่อากิวเมนต์ของฟังก์ชั่นเพื่อให้มันเป็นคำสั่งเดียวลบ{}และบันทึกอีกสองไบต์
จูเซปเป้

@Giuseppe Darn ยังคงลืมไปว่าคุณสามารถกำหนดได้ในฟังก์ชัน args ใช้เวลาสักสองสามนาทีเพื่อลองเปลี่ยนตัวแปรเหล่านั้น ...
Vlo

8

Pyth , 24 ไบต์

sm*Fmc@@Qhkek2d{mScd2.pU

ลองที่นี่!


รุ่นเก่า 35 ไบต์

*c1**FK/lQ2^2Ksm*Fm@@Q@dtyk@dykK.pU

ลองที่นี่!


3
ปัจจุบันเป็นผู้นำ แต่คุณต้องกลัวคำตอบของ Jelly ที่จะมา .... :)

Eh Jelly จะเอาชนะฉันไปได้ประมาณ 10 ไบต์ Pyth ไม่ใช่เครื่องมือที่ดีที่สุดสำหรับงาน
Mr. Xcoder

05AB1E ดูเหมือนว่ามันอาจจะผูก Pyth (เชื่อหรือไม่ในที่สุดความท้าทายเมทริกซ์ที่a[b]เพียงพอที่จะแข่งขัน)
Magic Octopus Urn

@ MagicOctopusUrn ฉันมีโซลูชัน 05AB1E ที่เต้น Pyth :-) แล้วจะไม่โพสต์ (ตอนนี้อย่างน้อยที่สุด)
Mr. Xcoder

มันเป็นบางสิ่งบางอย่างตามแนวของxÍysè<¹sès·<ysè<èlmao หรือไม่? พีเอสของฉันคือ 40 ไบต์และทำงานได้ไม่ดีฮะดังนั้นอย่าลังเลที่จะโพสต์ไม่แน่ใจว่าฉันจะเสร็จก่อนที่ฉันจะต้องกลับบ้าน
Magic Octopus Urn

6

Stax , 23 22 19 17 ไบต์

ü;Y╙◘▌Φq↓ê²╧▐å↑┌C

เรียกใช้และตรวจแก้จุดบกพร่องออนไลน์

การแสดง ascii ที่สอดคล้องกันของโปรแกรมเดียวกันคือสิ่งนี้

%r|TF2/{xsE@i^H/m:*+

โปรแกรมทนทุกข์ทรมานจากข้อผิดพลาดในการปัดเศษทศนิยมบางจุด โดยเฉพาะอย่างยิ่งจะรายงานแทน33673.5000000011 33673.5แต่ฉันคิดว่าความถูกต้องเป็นที่ยอมรับเนื่องจากโปรแกรมนี้ทำงานกับค่าทศนิยม นอกจากนี้ยังช้ามากใช้เวลาเกือบหนึ่งนาทีสำหรับตัวอย่างอินพุตในเครื่องนี้

%                             get size of matrix
 r|T                          get all permutations of [0 ... size-1]
    F                         for each, execute the rest of the program
     2/                       get consecutive pairs
       {        m             map each pair... 
        xsE@                      the matrix element at that location
            i^H/                  divided by 2*(i+1) where i=iteration index
                 :*           product of array
                   +          add to running total

1
ที่น่าประทับใจมาก!

5

05AB1E , 21 ไบต์

ā<œε2ô{}Ùεε`Isèsè;]PO

ลองออนไลน์!


รุ่นเก่า 32 ไบต์

āœvIg;©Lε·UIyX<èèyXèè}P}Oθ®!/®o/

ลองออนไลน์!

มันทำงานอย่างไร?

āœvIg;©Lε·UIyX<èèyXèè}P}Oθ®!/®o/ – Full program. Argument: A matrix M.
ā                                – The range [1 ... len(M)].
 œ                               – Permutations.
  v                    }         – Iterate over the above with a variable y.
   Ig;©                          – Push len(M) / 2 and also store it in register c.
       Lε            }           – For each integer in the range [1 ... ^]:
         ·U                      – Double it and store it in a variable X.
            yX<                  – Push the element of y at index X-1.
           I   è                 – And index with the result into M.
                yXè              – Push the element of y at index X.
                   è             – And index with the result into ^^.
                      P          – Take the product of the resulting list.
                        O        – Sum the result of the mapping.
                         θ       – And take the last element*.
                          ®!     – Take the factorial of the last item in register c.
                             ®o  – Raise 2 to the power of the last item in register c.
                            /  / – And divide the sum of the mapping accordingly.

* – Yeah, this is needed because I mess up the stack when pushing so many values in the loop and not popping correctly ;P

1
ไม่มีการล้อเล่นหรอกèsèฮ่า ๆ ... ฮ่าฮ่า ... ข้าโง่
Magic Octopus Urn

@MagicOctopusUrn คงที่ ... ฉันลืม 05AB1E ได้รับการจัดทำดัชนี 0> _ <
Mr. Xcoder

3

เยลลี่ขนาด 19 ไบต์

LŒ!s€2Ṣ€QḅL_LịFHP€S

ลองออนไลน์!

เวอร์ชันสำรอง 15 ไบต์โพสต์วันที่ท้าทาย

LŒ!s€2Ṣ€QœịHP€S

ในที่สุดเจลลี่ก็มีการจัดทำดัชนีอาร์เรย์ n มิติ

ลองออนไลน์!

มันทำงานอย่างไร

LŒ!s€2Ṣ€QœiHP€S  Main link. Argument: M (matrix / 2D array)

L                Take the length, yielding 2n.
 Œ!              Generate all permutations of [1, ..., 2n].
   s€2           Split each permutation into pairs.
      Ṣ€         Sort the pair arrays.
        Q        Unique; deduplicate the array of pair arrays.
                 This avoids dividing by n! at the end.
           H     Halve; yield M, with all of its elements divided by 2.
                 This avoids dividing by 2**n at the end.
         œị      At-index (n-dimensional); take each pair of indices [i, j] and
                 yield M[i][j].
            P€   Take the product the results corresponding the same permutation.
              S  Take the sum of the products.

เวอร์ชั่น 19 ไบต์ทำงานในลักษณะเดียวกัน มันแค่ต้องทำให้œịสำเร็จ

...ḅL_LịFH...    Return value: Array of arrays of index pairs. Argument: M

    L            Length; yield 2n.
   ḅ             Convert each pair of indices [i, j] from base 2n to integer,
                 yielding ((2n)i + j).
     _L          Subtract 2n, yielding ((2n)(i - 1) + j).
                 This is necessary because indexing is 1-based in Jelly, so the
                 index pair [1, 1] must map to index 1.
        F        Yield M, flattened.
       ị         Take the indices to the left and get the element at these indices
                 from the array to the right.
         H       Halve; divide all retrieved elements by 2.

3

C (gcc) , 288 285 282 293 292 272 271 ไบต์

  • บันทึกสามไบต์โดยเล่นซอโดยมีการเพิ่มทีละสองครั้งและสำหรับการจัดวางแบบวนซ้ำ
  • บันทึกสามไบต์โดยเล่นซอกับ anothter post-increment ย้ายทั้งการกำหนดค่าเริ่มต้นตัวแปรก่อนที่สาขา - golfed if(...)...k=0...else...,j=0...ไปที่if(k=j=0,...)...else...- และดำเนินการเปลี่ยนดัชนี
  • จำเป็นต้องมีสิบเอ็ดไบต์โดยสนับสนุนfloatเมทริกซ์
  • บันทึกเป็นไบต์ขอบคุณMr. Xcoder ; การเล่นกอล์ฟไป2*j+++1j-~j++
  • บันทึกไว้ยี่สิบไบต์โดยการลบการintประกาศประเภทตัวแปรฟุ่มเฟือยและไม่ได้ใช้ฟังก์ชันแฟกทอเรียล แต่แทนที่จะคำนวณค่าแฟกทอเรียลโดยใช้ค่าที่มีอยู่แล้วสำหรับลูป
  • บันทึกไบต์โดยการเล่นกอล์ฟไปS=S/F/(1<<n);S/=F*(1<<n);
float S,p,F;j,i;s(A,n,P,l,o,k)float*A;int*P;{if(k=j=0,o-l)for(;k<l;s(A,n,P,l,o+1))P[o]=k++;else{for(p=-l;j<l;j++)for(i=0;i<l;)p+=P[j]==P[i++];if(!p){for(F=p=1,j=0;j<n;F*=j)p*=A[P[2*j]*2*n+P[j-~j++]];S+=p;}}}float h(A,n)float*A;{int P[j=2*n];S=0;s(A,n,P,j,0);S/=F*(1<<n);}

ลองออนไลน์!

คำอธิบาย

float S,p,F;                    // global float variables: total sum, temporary, factorial
j,i;                            // global integer variables: indices
s(A,n,P,l,o,k)float*A;int*P;{   // recursively look at every permutation in S_n
 if(k=j=0,o-l)                  // initialize k and j, check if o != l (possible  permutation not yet fully generated)
  for(;k<l;s(A,n,P,l,o+1))      // loop through possible values for current possible  permuation position
   P[o]=k++;                    // set possible  permutation, recursively call (golfed into the for loop)
 else{for(p=-l;j<l;j++)         // there exists a possible permutation fully generated
  for(i=0;i<l;)                 // test if the possible permutation is a bijection
   p+=P[j]==P[i++];             // check for unique elements
  if(!p){                       // indeed, it is a permutation
   for(F=p=1,j=0;j<n;F*=j)      // Hafnian product loop and calculate the factorial (over and over to save bytes)
    p*=A[P[2*j]*2*n+P[j-~j++]]; // Hafnian product
   S+=p;}}}                     // add to sum
float h(A,n)float*A;{           // Hafnian function
 int P[j=2*n];S=0;              // allocate permutation memory, initialize sum
 s(A,n,P,j,0);                  // calculate Hafnian sum
 S/=F*(1<<n);}                  // calculate Hafnian

ลองออนไลน์!

ที่แกนกลางของโปรแกรมเป็นตัวกำเนิดการเปลี่ยนแปลงต่อไปนี้ซึ่งวนS_nซ้ำไปมา การคำนวณทั้งหมดของ Hafnian เป็นเพียงแค่สร้างมันขึ้นมาและเล่นกอล์ฟต่อไป

j,i,p;Sn(A,l,o,k)int*A;{          // compute every element in S_n
 if(o-l)                          // o!=l, the permutation has not fully been generated
  for(k=0;k<l;k++)                // loop through the integers [0, n)
   A[o]=k,Sn(A,l,o+1);            // modify permutation, call recursively
 else{                            // possible permutation has been generated
  for(p=-l,j=0;j<l;j++)           // look at the entire possible permutation
   for(i=0;i<l;i++)p+=A[j]==A[i]; // check that all elements appear uniquely
  if(!p)                          // no duplicat elements, it is indeed a permutation
   for(printf("["),j=0;j<l        // print
   ||printf("]\n")*0;)            //  the
    printf("%d, ",A[j++]);}}      //   permutation
main(){int l=4,A[l];Sn(A,l,0);}   // all permutations in S_4

ลองออนไลน์!


1
ดีที่มีคำตอบ C แต่ตามที่คุณแนะนำมันไม่สอดคล้องกับปัจจุบัน

@Lembik คงที่ ตอนนี้รองรับfloatเมทริกซ์
Jonathan Frech

2*j+++1เทียบเท่ากับj+j+++1ซึ่งเหมือนกันj-(-j++-1)ดังนั้นเราจึงสามารถใช้บิตเสริมได้อย่างมีประสิทธิภาพเพื่อบันทึกไบต์: j-~j++( ลองออนไลน์ )
Mr. Xcoder

3

R , 84 78 ไบต์

h=function(m)"if"(n<-nrow(m),{for(j in 2:n)F=F+m[1,j]*h(m[v<--c(1,j),v]);F},1)

ลองออนไลน์!

แก้ไข: ขอบคุณ Vlo สำหรับ -6 ไบต์

ดูเหมือนว่าทุกคนที่นี่คือการใช้ขั้นตอนวิธีการอ้างอิงกับมาตรฐานพีชคณิต แต่ผมพยายามที่จะใช้ประโยชน์จากความรู้ที่ชุมชนได้รับในความท้าทายที่เกี่ยวข้องซึ่งเป็นพื้นงานเดียวกันกำหนดเป้าหมายสำหรับรหัสที่เร็วที่สุดแทนการกอล์ฟ

ปรากฎว่าสำหรับภาษาที่เก่งในการตัดเมทริกซ์ (เช่น R) อัลกอริทึมแบบเรียกซ้ำ: hafnian(m) = sum(m[i,j] * hafnian(m[-rows and columns at i,j])ไม่เพียง แต่เร็วขึ้น แต่ยังค่อนข้างกอล์ฟ นี่คือรหัส ungolfed:

hafnian<-function(m)
{
    n=nrow(m)
    #Exits one step earlier than golfed version
    if(n == 2) return(m[1,2])
    h = 0
    for(j in 2:n) {
        if(m[1,j] == 0) next
        h = h + m[1,j] * hafnian(m[c(-1,-j),c(-1,-j)])
    }
    h
}

คำตอบที่ดีมาก -1 สำหรับการโทรIfด้วยวงเล็บ -4 สำหรับการใช้Fเป็นตัวแปรเริ่มต้น -1 สำหรับการกำหนดภายในn tio.run/##XU/LCsIwELz7FcFTVtOQl1pf1/ …if
Vlo

เรียบร้อย! ฉันจะบอกว่าโพสต์ในการท้าทายความเร็ว แต่อาจมีการเพิ่มประสิทธิภาพบางอย่างเพิ่มเติม (เช่นเธรด) ที่สามารถทำได้และในขณะที่ R ไม่เป็นที่รู้จักสำหรับความเร็วของมันมันจะดีถ้ามีไว้สำหรับอ้างอิง .
Giuseppe

ทำเพื่อวัตถุประสงค์มาตรฐาน!
Vlo

จริง ๆ แล้วฉันพยายามทดสอบความเร็วนี้ แต่ผลลัพธ์ก็ท้อแท้อย่างรวดเร็ว การส่ง Python ที่ช้าที่สุดในความท้าทายด้านความเร็วโดยใช้อัลกอริทึมที่แน่นอนแบบเดียวกันจะทำการแมทชิ่ง 24x24 ในเวลาไม่กี่วินาทีบน TIO แต่ R หมดเวลา บนเครื่องในท้องถิ่นของฉันมันก็ไม่ตอบสนองในเวลาที่เหมาะสมแม้เมื่อได้รับความช่วยเหลือจากการบันทึกจากแพ็คเกจ 'memo' ...
Kirill L.

2

เยลลี่ 29 ไบต์

LHµ2*×!
LŒ!s€2;@€€Wị@/€€P€S÷Ç

ลองออนไลน์!

ฉันคิดว่า;@€€Wị@/€€P€ตอนนี้สามารถเล่นกอล์ฟได้ ต้องกลับมาใหม่ภายหลังเพื่อตรวจสอบและเพิ่มคำอธิบาย


เหมือนกับโซลูชันของฉัน(ยกเว้นJ) ก่อนลงสนาม จิตใจของเยลลี่คิดเหมือนกันไหม? source
user202729

ฉันสามารถลดมันได้อีกเล็กน้อยโดยปรับโครงสร้างส่วนที่คุณพูดถึงรวมถึงการหารด้วย 2 และแฟคทอเรียล LḶŒ!s€2ḅL‘ịFZµPS÷JḤ$P$ TIO
ไมล์

@ user202729 haha ​​nice
dylnan

@miles Wow นั้นเป็นเงินออมจำนวนมาก ฉันจะแก้ไขมันกลายเป็นคำตอบของฉัน แต่มันเป็นเรื่องที่แตกต่างกันเพื่อให้สวยอย่าลังเลที่จะส่งคำตอบของคุณเองหากคุณต้องการ
dylnan


2

MATL , 29 24 22 ไบต์

Zy:Y@!"G@2eZ{)tn:E/pvs

ลองออนไลน์! หรือตรวจสอบทุกกรณีทดสอบ: 1 , 2 , 3

มันทำงานอย่างไร

Zy       % Size of (implicit) input: pushes [2*n 2*n], where the
         % input is a 2*n × 2*n matrix. 
:        % Range: gives row vector [1 2 ... 2*n]
Y@       % All permutation of that vector as rows of a matrix
!"       % For each permutation 
  G      %   Push input matrix
  @      %   Push current permutation
  2e     %   Reshape as a 2-row array
  Z{     %   Split rows into a cell array of size 2
  )      %   Reference indexing. With a cell array as index this
         %   applies element-wise indexing (similar to sub2ind).
         %   Gives a row vector with the n matrix entries selected
         %   by the current permutation
  t      %   Duplicate
  n:     %   Number of elements, range: this gives [1 2 ... n]
  E      %   Double, element-wise: gives [2 4 ... 2*n]
  /      %   Divide, element-wise
  p      %   Product
  vs     %   Vertically concatenate and sum
         % End (implicit). Display (implicit)



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