Codegolf the Hafnian

22

Tantangannya adalah menulis codegolf untuk Hafnian dari sebuah matriks . The Hafnian dari 2n-by- 2nmatriks simetris Adidefinisikan sebagai:

masukkan deskripsi gambar di sini

Di sini S 2n mewakili set semua permutasi bilangan bulat dari 1ke2n , yaitu [1, 2n].

Tautan wikipedia berbicara tentang matriks kedekatan tetapi kode Anda harus berfungsi untuk matriks masukan simetris yang bernilai nyata.

Bagi mereka yang tertarik pada aplikasi Hafnian, tautan mathoverflow membahas lebih banyak lagi.

Namun kode Anda dapat mengambil input yang diinginkan dan memberikan output dalam format apa pun yang masuk akal, tetapi harap sertakan dalam jawaban Anda contoh yang lengkap, termasuk instruksi yang jelas tentang cara memasok input ke kode Anda.

Matriks input selalu berbentuk bujur sangkar dan paling banyak 16 x 16. Tidak perlu lagi menangani matriks kosong atau matriks dimensi ganjil.

Implementasi referensi

Berikut ini beberapa contoh kode python dari 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

Halaman wiki sekarang (2 Maret 2018) telah diperbarui oleh ShreevatsaR untuk memasukkan cara berbeda dalam menghitung Hafnian. Akan sangat menarik melihat golf ini.

pengguna202729
sumber
5
Saya pikir ini akan lebih mudah dicerna dengan penjelasan informal tentang hafnian. Sesuatu seperti, ambil semua himpunan bagian dari entri matriks di mana indeks baris n dan indeks kolom membentuk partisi dari 1..2n, ambil produk dari masing-masing, tambahkan, dan skala jumlahnya.
xnor

Jawaban:

9

R , 150 142 127 119 byte

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)

Cobalah online!

Menggunakan trik yang sama saya menemukan golf jawaban ini untuk mengindeks matriks P, dan @Vo menyarankan pendekatan untuk menghapus sepenuhnyafor loop untuk -6 byte!

Untuk membuat test case baru, Anda bisa melakukannya matrix(c(values,separated,by,commas,going,across,rows),nrow=2n,ncol=2n,byrow=T) .

Penjelasan: (kodenya sama; ia menggunakan applybukan forloop tetapi logikanya identik).

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
}

Giuseppe
sumber
Terapkan lebih murah dengan 2 byte, yang memungkinkan untuk tambahan 4 byte penghematan dengan menjejalkan garis lainnya bersama-sama. tio.run/##PY6xDoIwEIZ3nsLxzpxiS4ymkYEXYHIjDFDEEKBtSokS47PX4sDw5/... Juga cukup menarik bagaimana basis R tidak memiliki fungsi permutasi untuk bahasa pemrograman statistik
Vlo
@Vo sangat bagus! kita bisa pindah Ndan kke argumen fungsi untuk mendapatkannya ke satu pernyataan, menghapus {}dan menyimpan dua byte lainnya.
Giuseppe
@Giuseppe Darn terus lupa bahwa Anda dapat mendefinisikannya di argumen fungsi. Menghabiskan beberapa menit untuk mencoba variabel-variabel itu ...
Vlo
8

Pyth , 24 byte

sm*Fmc@@Qhkek2d{mScd2.pU

Coba di sini!


Versi lama, 35 byte

*c1**FK/lQ2^2Ksm*Fm@@Q@[email protected]

Coba di sini!

Tuan Xcoder
sumber
3
Saat ini memimpin tetapi Anda harus takut jawaban Jelly datang .... :)
Eh Jelly pasti akan mengalahkan saya sekitar 10 byte. Pyth bukan alat terbaik untuk pekerjaan itu
Tn. Xcoder
05AB1E terlihat seperti itu bahkan dapat mengikat Pyth (percaya atau tidak, akhirnya tantangan matriks di mana a[b]cukup untuk bersaing).
Magic Octopus Urn
@ MagicOctopusUrn Saya sudah punya solusi 05AB1E yang mengalahkan Pyth :-) Tidak akan mempostingnya (untuk saat ini, setidaknya)
Mr. Xcoder
Apakah ada sesuatu yang sejalan dengan xÍysè<¹sès·<ysè<èlmao? Tambang PS adalah 40 byte dan tidak berfungsi dengan baik hah, jadi jangan ragu untuk mempostingnya, tidak yakin saya bisa menyelesaikannya sebelum saya harus pulang.
Magic Octopus Urn
6

Stax , 23 22 19 17 byte

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

Jalankan dan debug secara online

Representasi ascii yang sesuai dari program yang sama adalah ini.

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

Program ini menderita beberapa kesalahan pembulatan titik mengambang. Secara khusus, ini melaporkan 33673.5000000011bukan 33673.5. Tapi saya pikir akurasinya dapat diterima mengingat bahwa program ini beroperasi pada nilai floating point. Ini juga sangat lambat, mengambil hampir satu menit untuk input contoh pada mesin ini.

%                             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
rekursif
sumber
1
Sangat mengesankan!
5

05AB1E , 21 byte

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

Cobalah online!


Versi lama, 32 byte

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

Cobalah online!

Bagaimana itu bekerja?

āœ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
Tuan Xcoder
sumber
1
Jangan bercanda èsè, hah ... haha ​​... aku lemah.
Magic Octopus Urn
@MagicOctopusUrn Diperbaiki ... Saya lupa 05AB1E 0-diindeks> _ <
Tn. Xcoder
3

Jelly , 19 byte

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

Cobalah online!

Versi alternatif, 15 byte, tantangan tanggal kiriman

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

Jelly akhirnya mendapat pengindeksan array n-dimensi.

Cobalah online!

Bagaimana itu bekerja

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.

Versi 19-byte bekerja dengan cara yang sama; hanya harus mengimplementasikannya œịsendiri.

...ḅ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.
Dennis
sumber
3

C (gcc) , 288 285 282 293 292 272 271 byte

  • Disimpan tiga byte dengan mengutak-atik dua kenaikan pasca dan untuk penempatan loop.
  • Disimpan tiga byte dengan mengutak-atik penambahan setelahnya, menggerakkan kedua inisialisasi variabel sebelum cabang - golf if(...)...k=0...else...,j=0... keif(k=j=0,...)...else... - dan melakukan pergeseran indeks.
  • Diperlukan sebelas byte dengan mendukung float matriks.
  • Menyimpan satu byte berkat Tn. Xcoder ; bermain golf2*j+++1 untukj-~j++ .
  • Disimpan dua puluh byte dengan menghapus berlebihan int deklarasi tipe variabel dan tidak menggunakan fungsi faktorial melainkan menghitung nilai faktorial dengan menggunakan yang sudah ada untuk loop.
  • Disimpan satu byte dengan bermain golf S=S/F/(1<<n);ke 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);}

Cobalah online!

Penjelasan

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

Cobalah online!

Pada intinya program adalah generator permutasi berikut yang dilewati S_n. Semua perhitungan Hafnian hanya dibangun di atasnya - dan golf lebih lanjut.

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

Cobalah online!

Jonathan Frech
sumber
1
Sangat bagus memiliki jawaban C tetapi, seperti yang Anda sarankan, saat ini tidak sesuai.
@Lembik Diperbaiki. Sekarang mendukung floatmatriks.
Jonathan Frech
2*j+++1sama dengan j+j+++1, yang sama dengan j-(-j++-1), jadi kita dapat menggunakan bitwise melengkapi secara efisien untuk menghemat byte: j-~j++( Coba online )
Mr. Xcoder
3

R , 84 78 byte

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)

Cobalah online!

Sunting: Terima kasih kepada Vlo untuk -6 byte.

Tampaknya semua orang di sini menerapkan algoritma referensi standar dengan permutasi, tetapi saya mencoba mengambil keuntungan dari pengetahuan masyarakat yang diperoleh di tantangan terkait , yang pada dasarnya adalah tugas yang sama yang ditargetkan untuk kode tercepat daripada golf.

Ternyata untuk bahasa yang bagus dalam mengiris matriks (seperti R), algoritma rekursif: hafnian(m) = sum(m[i,j] * hafnian(m[-rows and columns at i,j])tidak hanya lebih cepat, tetapi juga cukup golf. Berikut adalah kode yang tidak dipisahkan:

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
}
Kirill L.
sumber
Jawaban yang sangat bagus -1 untuk memanggil Ifdengan tanda kurung, -4 untuk menggunakan Fsebagai variabel diinisialisasi, -1 untuk menetapkan ndalam if. tio.run/##XU/LCsIwELz7FcFTVtOQl1pf1/…
Vlo
rapi! Saya akan mengatakan mempostingnya dalam tantangan kecepatan, tetapi mungkin ada beberapa optimasi lainnya (seperti threading) yang dapat dibuat, dan sementara R tidak benar-benar dikenal karena kecepatannya, akan baik untuk memilikinya di sana untuk referensi .
Giuseppe
Lakukan untuk tujuan benchmark!
Vlo
Saya benar-benar mencoba menguji kecepatan ini, tetapi dengan cepat berkecil hati oleh hasilnya. Penyerahan Python paling lambat dalam tantangan kecepatan menggunakan algoritme tepat yang sama menghasilkan matriks 24x24 dalam beberapa detik pada TIO, tetapi R kali habis. Di mesin lokal saya, itu juga tidak merespons dalam waktu yang wajar, bahkan ketika dibantu dengan memoisasi dari paket 'memo' ...
Kirill L.
2

Jelly , 29 byte

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

Cobalah online!

Saya pikir ;@€€Wị@/€€P€bagian kemungkinan bisa diturunkan. Perlu kembali lagi nanti untuk memeriksa dan menambahkan penjelasan.

dylnan
sumber
Identik dengan solusi saya (kecuali yang J) sebelum bermain golf . Pikiran jeli berpikir sama ? sumber
user202729
Saya bisa mengurangi sedikit lebih banyak dengan refactoring bagian yang Anda sebutkan serta pembagian oleh 2 dan faktorial. LḶŒ!s€2ḅL‘ịFZµPS÷JḤ$P$ TIO
mil
@ user202729 haha ​​bagus
dylnan
@miles Wow itu banyak penghematan. Saya akan mengeditnya menjadi jawaban saya tetapi sangat berbeda jadi silakan kirimkan jawaban Anda sendiri jika Anda mau
dylnan
2

Haskell , 136 byte

-14 byte berkat ovs.

import Data.List
f m|n<-length m`div`2=sum[product[m!!(s!!(2*j-2)-1)!!(s!!(2*j-1)-1)/realToFrac(2*j)|j<-[1..n]]|s<-permutations[1..n*2]]

Cobalah online!

Ugh ...

benar-benar manusiawi
sumber
2

MATL , 29 24 22 byte

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

Cobalah online! Atau verifikasi semua kasus uji: 1 , 2 , 3 .

Bagaimana itu bekerja

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)
Luis Mendo
sumber
1

Coconut , 165 145 128 127 byte

-1 byte terima kasih kepada Tn. Xcoder

m->sum(reduce((o,j)->o*m[p[2*j]][p[j-~j]]/-~j/2,range(len(m)//2),1)for p in permutations(range(len(m))))
from itertools import*

Cobalah online!

ovs
sumber
1

Perl 6, 86 byte

{my \n=$^m/2;^$m .permutations.map({[*] .map(->\a,\b{$m[a][b]})}).sum/(2**n*[*] 1..n)}
bb94
sumber