Codegolf Hafnian


22

Buradaki zorluk, bir matrisin Hafniyenine kod yazarı yazmaktır . Bir simetrik matrisin 2nHafnian'ı şöyle tanımlanır:2nA

görüntü tanımını buraya girin

İşte S 2n gelen sayının tüm permütasyon kümesini temsil 1etmek 2nolduğunu, [1, 2n].

Wikipedia bağlantı bitişik matrisler hakkında konuşuyor, ancak kodunuz gerçek değerli simetrik girdi matrisleri için çalışmalıdır.

Hafnian'ın uygulamalarıyla ilgilenenler için, mathoverflow bağlantısı biraz daha tartışıyor.

Kodunuz istediği şekilde girdi alabilir ve herhangi bir makul formatta çıktı verebilir, ancak lütfen cevabınıza kodunuza nasıl girdi sağlayacağınızla ilgili açık talimatlar içeren eksiksiz bir çalışılmış örnek ekleyin.

Giriş matrisi her zaman kare şeklindedir ve 16 ile 16 arasında olacaktır. Boş matrisi veya tek boyutlu matrisleri kullanmaya gerek yoktur.

Referans uygulaması

İşte Bay Xcoder'dan bir örnek python kodu.

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 sayfası şimdi (2 Mart 2018), ShreevatsaR tarafından Hafnian'ı hesaplamanın farklı bir yolunu içerecek şekilde güncellendi. Bunu golf oynamak çok ilginç olurdu.


5
Bunun hafnian'ın gayriresmi bir açıklaması ile hazmetmesinin daha kolay olacağını düşünüyorum. Gibi bir şey, n satır endeksleri ve n sütun endekslerinin 1..2n'lik bir bölüm oluşturduğu n matris girişlerinin tüm alt kümelerini alın, her birinin ürününü alın, ekleyin ve toplamı ölçeklendirin.
xnor

Yanıtlar:


9

R, , 150 142 127 119 bayt

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)

Çevrimiçi deneyin!

Bu hileyi kullanarak matrisi indekslemek için bu cevabı aşağı bulduğumu keşfettim Pve @Vlofor , -6 byte için döngüyü tamamen kaldırmak için bir yaklaşım önerdi !

Yeni bir test durumu oluşturmak için yapabilirsiniz matrix(c(values,separated,by,commas,going,across,rows),nrow=2n,ncol=2n,byrow=T).

Açıklama: (kod aynıdır; applybir fordöngü yerine bir döngü kullanır ancak mantık aynıdır).

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
}


Apply (Uygula), 2 satır daha ucuzdur; bu, diğer satırları bir araya getirerek ek 4 baytlık tasarruf sağlar. tio.run/##PY6xDoIwEIZ3nsLxzpxiS4ymkYEXYHIjDFDEEKBtSokS47PX4sDw5/… Temel R'nin istatistiksel programlama dili için bir permütasyon işlevinden yoksun olması da oldukça ilginç
Vlo

@Vlo çok güzel! bir ifadeye almak, başka iki byte'ı kaldırmak ve saklamak için işlev argümanlarına girebilir Nve kişlev değişkenlerine girebiliriz {}.
Giuseppe

@Giuseppe Darn, onları fonksiyon argümanlarında tanımlayabileceğinizi unutmaya devam ediyor. Bu değişkenleri
kıpırdatmaya

8

Pyth , 24 bayt

sm*Fmc@@Qhkek2d{mScd2.pU

Burada dene!


Eski versiyon, 35 bayt

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

Burada dene!


3
Şu anda liderlik ama

Eh Jelly kesinlikle benim yaklaşık 10 bayt tarafından yenecek. Pyth iş için en iyi araç değil
Bay Xcoder

05AB1E, Pyth'i bile bağlayabilir gibi görünüyor (ister inan ister inanma, sonunda a[b]rekabet etmek için yeterli olan bir matris mücadelesi ).
Magic Octopus Urn

@MagicOctopusUrn Zaten Pyth'i yenen bir 05AB1E çözümüm var :-) Göndermeyeceğim (en azından şu an için)
Bay Xcoder

xÍysè<¹sès·<ysè<èİmao çizgisinde bir şey mi var? PS Mine 40 bayttır ve çok iyi çalışmaz, eve göndermeden önce bitirebileceğimden emin değilim.
Magic Octopus Urn

6

Stax , 23 22 19 17 bayt

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

Çevrimiçi çalıştırın ve hata ayıklayın

Aynı programın karşılık gelen ascii gösterimi budur.

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

Program bazı kayar nokta yuvarlama hatasından muzdarip. Özellikle, 33673.5000000011yerine raporlar 33673.5. Ancak, bu programın kayan nokta değerleri üzerinde çalışması durumunda doğruluğun kabul edilebilir olduğunu düşünüyorum. Ayrıca bu makinedeki örnek girişler için neredeyse bir dakika süren çok yavaş.

%                             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
Çok etkileyici!

5

05AB1E , 21 bayt

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

Çevrimiçi deneyin!


Eski versiyon, 32 bayt

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

Çevrimiçi deneyin!

Nasıl çalışır?

āœ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
Şaka yok èsè, hah ... haha ​​... Ben cılız.
Magic Octopus Urn

@MagicOctopusUrn Sabit ... Unuttum 05AB1E 0-indeksli> _ <
Bay Xcoder

3

Jöle , 19 bayt

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

Çevrimiçi deneyin!

Alternatif sürüm, 15 bayt, kayıt sonrası yükleme

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

Jelly sonunda n boyutlu dizi indekslemesi yaptı.

Çevrimiçi deneyin!

Nasıl çalışır

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 baytlık sürüm benzer şekilde çalışır; sadece œịkendini uygulamak zorunda .

...ḅ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 bayt

  • İki artımlı yükselterek ve ilmek yerleştirme ile üç bayt kurtarıldı.
  • Daldan önce her iki değişken başlatmayı hareket ettirerek artımlı artımlı artışla uğraşarak üç bayt kurtardı if(...)...k=0...else...,j=0...-if(k=j=0,...)...else... - ve bir indeks kayma gerçekleştirilir.
  • Destekleyerek gerekli onbir bayt floatMatrisleri .
  • Sayesinde bir bayt kaydedildi Bay Xcoder kurtardı ; golf 2*j+++1içinj-~j++ .
  • Gereksizleri kaldırarak yirmi bayt kaydedildi int değişken tipi bildirimini ve faktöriyel bir işlev kullanmadan, ancak bunun yerine zaten döngü için var olan faktoring değerini hesaplayarak .
  • Golf tarafından bayt Kaydedilen S=S/F/(1<<n);içinS/=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);}

Çevrimiçi deneyin!

açıklama

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

Çevrimiçi deneyin!

Programın özünde, içinden geçen aşağıdaki permütasyon üreteci var S_n. Tüm Hafnian hesaplamaları basitçe üzerine inşa edilmiştir - ve daha da golf oynar.

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

Çevrimiçi deneyin!


1
C cevabı almak harika ancak sizin de belirttiğiniz gibi, şu anda uyumlu değil.

@Lembik Sabit. Şimdi floatmatrisleri destekliyor .
Jonathan Frech

2*j+++1eşdeğer olduğunu j+j+++1aynıdır, j-(-j++-1)biz bir byte kaydetmek için verimli bit cinsinden eşleniğini kullanabilmesi: j-~j++( çevrimiçi deneyin )
Sayın Xcoder

3

R , 84 78 bayt

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)

Çevrimiçi deneyin!

Düzenleme: -6 bayt için Vlo teşekkürler.

Görünüşe göre buradaki herkes standart referans algoritmasını permütasyonlarla uyguluyor, ancak ilgili zorlukta edinilen topluluk bilgisinden yararlanmaya çalıştım. temelde golf yerine en hızlı kod için hedeflenen aynı görev olan .

Matris dilimlemede iyi olan bir dil için (R gibi), özyinelemeli algoritmanın: hafnian(m) = sum(m[i,j] * hafnian(m[-rows and columns at i,j])sadece daha hızlı değil, aynı zamanda oldukça golf gibi olduğu ortaya çıktı. İşte kodlanmamış kod:

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
}

Çok güzel cevap. IfParantezle çağırmak için -1 , Fbaşlatılmış değişken olarak kullanmak için -4 , niçinde atamak için -1 if. tio.run/##XU/LCsIwELz7FcFTVtOQl1pf1/…
Vlo

düzgün! Bunu hız mücadelesinde yayınlayacağım derdim, ama muhtemelen yapılabilecek bazı daha fazla optimizasyon (iş parçacığı gibi) vardır ve R tam olarak hızı ile bilinmese de, referans olması için orada olması iyi olur. .
Giuseppe

Kıyaslama amacıyla yapın!
Vlo

Aslında bunu hız için test etmeye çalıştım, ancak sonuçlardan hemen vazgeçtim. Aynı kesin algoritmayı kullanarak hız mücadelesinde en yavaş Python sunumu, TIO'da birkaç saniye içinde 24x24 matrisini sıkıştırır, ancak R zaman aşımına uğrar. Yerel makinemde, 'memo' paketinden gelen notlara yardımcı olsa bile, makul bir sürede yanıt vermedi ...
Kirill L.

2

Jöle , 29 bayt

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

Çevrimiçi deneyin!

;@€€Wị@/€€P€Parçanın muhtemelen golf oynayabileceğini düşünüyorum . Bir açıklama kontrol etmek ve eklemek için daha sonra geri gelmeniz gerekiyor.


Benim Özdeş solüsyon (hariç J) önce aşağı golfed . Jelly beyinleri aynı düşünüyor mu? kaynak
user202729

Bahsettiğiniz kısmı, bölüm 2 ve faktörlük bölümlerini yeniden düzenleyerek biraz daha azaltabiliyordum. LḶŒ!s€2ḅL‘ịFZµPS÷JḤ$P$ TIO
mil

@ user202729 güzel haha
dylnan

@miles Vay bu çok tasarruf. Cevabımı düzenleyeceğim ama oldukça farklı, bu yüzden eğer istersen kendi cevabını göndermekten
çekinme

2

Haskell , 136 bayt

Ovs sayesinde -14 bayt.

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]]

Çevrimiçi deneyin!

Ahh ...


2

MATL , 29 24 22 bayt

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

Çevrimiçi deneyin! Veya tüm test durumlarını doğrulayın: 1 , 2 , 3 .

Nasıl çalışır

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)


1

Hindistan Cevizi , 165 145 128 127 bayt

Bay Xcoder sayesinde -1 bayt

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*

Çevrimiçi deneyin!


1

Perl 6, 86 bayt

{my \n=$^m/2;^$m .permutations.map({[*] .map(->\a,\b{$m[a][b]})}).sum/(2**n*[*] 1..n)}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.