Codegolf người Hafnian


22

Thách thức là viết codegolf cho Hafnian của một ma trận . Các Hafnian của một 2n-by- 2nma trận đối xứng Ađược định nghĩa là:

nhập mô tả hình ảnh ở đây

Ở đây S 2n đại diện cho tập hợp tất cả các hoán vị của các số nguyên từ 1đến 2n, nghĩa là [1, 2n].

Liên kết wikipedia nói về ma trận kề, nhưng mã của bạn sẽ hoạt động cho bất kỳ ma trận đầu vào đối xứng có giá trị thực nào.

Đối với những người quan tâm đến các ứng dụng của Hafnian, liên kết mathoverflow sẽ thảo luận thêm.

Mã của bạn có thể nhận đầu vào theo ý muốn và cung cấp đầu ra ở bất kỳ định dạng hợp lý nào, nhưng vui lòng bao gồm trong câu trả lời của bạn một ví dụ hoạt động đầy đủ bao gồm các hướng dẫn rõ ràng về cách cung cấp đầu vào cho mã của bạn.

Ma trận đầu vào luôn luôn vuông và sẽ có nhiều nhất là 16 x 16. Không cần phải có khả năng xử lý ma trận trống hoặc ma trận có kích thước lẻ.

Thực hiện tham khảo

Dưới đây là một số ví dụ mã python từ ông 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

Trang wiki hiện tại (ngày 2 tháng 3 năm 2018) đã được ShreevatsaR cập nhật để bao gồm một cách tính Hafnian khác. Sẽ rất thú vị khi xem môn đánh gôn này.


5
Tôi nghĩ rằng điều này sẽ dễ tiêu hóa hơn với một lời giải thích không chính thức về hafnian. Một cái gì đó giống như, lấy tất cả các tập hợp con của n mục nhập ma trận trong đó các chỉ số n hàng và n chỉ số cột của chúng tạo thành một phân vùng 1..2n, lấy sản phẩm của từng mục, thêm chúng và chia tỷ lệ.
xnor

Câu trả lời:


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)

Hãy thử trực tuyến!

Sử dụng cùng một mẹo mà tôi đã phát hiện ra khi đánh golf câu trả lời này để lập chỉ mục ma trận P@Vlo đã đề xuất một cách tiếp cận để loại bỏ hoàn toàn forvòng lặp cho -6 byte!

Để tạo một trường hợp thử nghiệm mới, bạn có thể làm matrix(c(values,separated,by,commas,going,across,rows),nrow=2n,ncol=2n,byrow=T).

Giải thích: (mã giống nhau; nó sử dụng applymột forvòng lặp chứ không phải vòng lặp nhưng logic thì giống hệt nhau).

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
}


Áp dụng rẻ hơn 2 byte, cho phép tiết kiệm thêm 4 byte bằng cách nhồi nhét các dòng khác lại với nhau. tio.run/##PY6xDoIwEIZ3nsLxzpxiS4ymkYEXYHIjDFDEEKBtSokS47PX4sDw5/... Nó cũng khá thú vị như thế nào cơ sở R thiếu một hàm hoán vị cho một ngôn ngữ lập trình thống kê
VLO

@Vlo rất hay! chúng ta có thể di chuyển Nkvào các đối số hàm để đưa nó đến một câu lệnh, loại bỏ {}và lưu hai byte khác.
Giuseppe

@Giuseppe Darn tiếp tục quên rằng bạn có thể định nghĩa chúng trong hàm args. Dành vài phút để cố gắng phát ra các biến đó ...
Vlo

8

Bình thường , 24 byte

sm*Fmc@@Qhkek2d{mScd2.pU

Hãy thử nó ở đây!


Phiên bản cũ, 35 byte

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

Hãy thử nó ở đây!


3
Hiện đang là người dẫn đầu nhưng bạn phải lo sợ câu trả lời của Jelly sẽ xuất hiện .... :)

Eh Jelly chắc chắn sẽ đánh bại tôi khoảng 10 byte. Pyth không phải là công cụ tốt nhất cho công việc
Ông Xcoder

05AB1E trông giống như nó thậm chí có thể ràng buộc Pyth (tin hay không, cuối cùng là một thử thách ma trận, nơi a[b]đủ để cạnh tranh).
Bạch tuộc ma thuật Urn

@MagicOctopusUrn Tôi đã có một giải pháp 05AB1E đánh bại Pyth :-) Sẽ không đăng nó (ít nhất là bây giờ)
Ông Xcoder

Có phải cái gì đó dọc theo dòng của xÍysè<¹sès·<ysè<èlmao? PS Mine là 40 byte và không hoạt động tốt lắm hah, vì vậy hãy đăng nó lên, không chắc là tôi có thể hoàn thành trước khi tôi phải về nhà.
Bạch tuộc ma thuật Urn

6

Stax , 23 22 19 17 byte

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

Chạy và gỡ lỗi trực tuyến

Đại diện ascii tương ứng của cùng một chương trình là đây.

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

Chương trình bị một số lỗi làm tròn điểm nổi. Đặc biệt, nó báo cáo 33673.5000000011thay vì 33673.5. Nhưng tôi nghĩ độ chính xác có thể chấp nhận được khi chương trình này hoạt động dựa trên các giá trị dấu phẩy động. Nó cũng rất chậm, mất gần một phút cho các đầu vào ví dụ trên máy này.

%                             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
Rất ấn tượng!

5

05AB1E , 21 byte

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

Hãy thử trực tuyến!


Phiên bản cũ, 32 byte

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

Hãy thử trực tuyến!

Làm thế nào nó hoạt động?

āœ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
Không đùa đâu èsè, hah ... haha ​​... tôi đang chơi chữ.
Bạch tuộc ma thuật Urn

@MagicOctopusUrn Đã sửa ... Tôi quên 05AB1E là 0 chỉ mục> _ <
Ông Xcoder

3

Thạch , 19 byte

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

Hãy thử trực tuyến!

Phiên bản thay thế, 15 byte, thách thức postdates

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

Jelly cuối cùng đã có chỉ mục mảng n chiều.

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

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.

Phiên bản 19 byte hoạt động theo cách tương tự; nó chỉ phải œịtự thực hiện

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

  • Đã lưu ba byte bằng cách thay đổi hai lần tăng sau và cho vị trí vòng lặp.
  • Đã lưu ba byte bằng cách thay đổi mức tăng sau anothter, di chuyển cả hai khởi tạo biến trước khi nhánh - được chơi if(...)...k=0...else...,j=0...thànhif(k=j=0,...)...else... - và thực hiện thay đổi chỉ mục.
  • Yêu cầu mười một byte bằng cách hỗ trợ float ma trận.
  • Đã lưu một byte nhờ ông Xcoder ; chơi golf 2*j+++1đểj-~j++ .
  • Đã lưu hai mươi byte bằng cách loại bỏ một phần thừa int khai báo loại biến và không sử dụng hàm giai thừa mà thay vào đó, tính toán giá trị giai thừa bằng cách sử dụng vòng lặp đã có sẵn.
  • Lưu một byte bằng cách chơi golf 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);}

Hãy thử trực tuyến!

Giải trình

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

Hãy thử trực tuyến!

Tại lõi của chương trình là trình tạo hoán vị sau đây lặp lại S_n. Tất cả các tính toán của Hafnian chỉ đơn giản là dựa trên nó - và tiếp tục chơi gôn.

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

Hãy thử trực tuyến!


1
Thật tuyệt khi có câu trả lời C nhưng, như bạn đề xuất, hiện tại nó không tuân thủ.

@Lembik Đã sửa. Bây giờ hỗ trợ floatma trận.
Jonathan Frech

2*j+++1tương đương với j+j+++1, tương tự như j-(-j++-1)vậy, vì vậy chúng ta có thể sử dụng bổ sung bitwise một cách hiệu quả để lưu một byte: j-~j++( Dùng thử trực tuyến )
Ông 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)

Hãy thử trực tuyến!

Chỉnh sửa: Nhờ Vlo cho -6 byte.

Dường như mọi người ở đây đang thực hiện thuật toán tham chiếu tiêu chuẩn với hoán vị, nhưng tôi đã cố gắng tận dụng kiến ​​thức cộng đồng thu được trong thử thách liên quan , về cơ bản là cùng một nhiệm vụ được nhắm mục tiêu cho mã nhanh nhất thay vì golf.

Nó chỉ ra rằng đối với một ngôn ngữ giỏi trong việc cắt các ma trận (như R), thuật toán đệ quy: hafnian(m) = sum(m[i,j] * hafnian(m[-rows and columns at i,j])không chỉ nhanh hơn, mà còn khá golf. Đây là mã không được mã hóa:

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
}

Câu trả lời rất hay. -1 để gọi Ifvới dấu ngoặc đơn, -4 để sử dụng Flàm biến khởi tạo, -1 để gán ntrong if. tio.run/##XU/LCsIwELz7FcFTVtOQl1pf1/ Kẻ
Vlo

khéo léo! Tôi muốn nói rằng hãy đăng nó trong thử thách tốc độ, nhưng có thể có một số tối ưu hóa khác (như xâu chuỗi) có thể được thực hiện, và trong khi R không biết chính xác về tốc độ của nó, thì thật tốt khi có nó ở đó để tham khảo .
Giuseppe

Làm điều đó cho mục đích điểm chuẩn!
Vlo

Tôi thực sự đã thử kiểm tra tốc độ này, nhưng đã nhanh chóng nản lòng với kết quả. Việc gửi Python chậm nhất trong thử thách tốc độ bằng cách sử dụng cùng một thuật toán chính xác sẽ phá vỡ ma trận 24x24 trong vài giây trên TIO, nhưng R hết thời gian. Trên máy cục bộ của tôi, nó cũng không phản hồi trong một thời gian hợp lý, ngay cả khi được hỗ trợ ghi nhớ từ gói 'ghi nhớ' ...
Kirill L.

2

Thạch , 29 byte

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

Hãy thử trực tuyến!

Tôi nghĩ rằng ;@€€Wị@/€€P€phần có thể có thể được đánh golf xuống. Cần quay lại sau để kiểm tra và thêm một lời giải thích.


Đồng nhất với giải pháp của tôi (trừ J) trước khi đánh golf xuống . Tâm trí Jelly có giống nhau không? nguồn
user202729

Tôi đã có thể giảm nó thêm một chút bằng cách tái cấu trúc phần mà bạn đã đề cập cũng như chia cho 2 và giai thừa. LḶŒ!s€2ḅL‘ịFZµPS÷JḤ$P$ TIO
dặm

@ user202729 haha ​​tốt đẹp
dylnan

@miles Wow đó là rất nhiều tiết kiệm. Tôi sẽ chỉnh sửa nó thành câu trả lời của tôi nhưng nó khá khác biệt, vì vậy, vui lòng gửi câu trả lời của riêng bạn nếu bạn muốn
dylnan


2

MATL , 29 24 22 byte

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

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp kiểm tra: 1 , 2 , 3 .

Làm thế nào nó hoạt động

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

Perl 6, 86 byte

{my \n=$^m/2;^$m .permutations.map({[*] .map(->\a,\b{$m[a][b]})}).sum/(2**n*[*] 1..n)}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.