जितनी जल्दी हो सके हफियन की गणना करें


12

चुनौती यह है कि मैट्रिक्स के हफियन की गणना के लिए सबसे तेज़ कोड लिखना संभव हो ।

एक सममितीय 2n- 2nमैट्रिक्स के हफियन को इस प्रकार Aपरिभाषित किया गया है:

यहाँ S 2n पूर्णांक के सभी क्रमपरिवर्तन के सेट को दर्शाता 1है 2n, जो कि है [1, 2n]

विकिपीडिया लिंक एक अलग दिखने वाला सूत्र भी देता है, जो ब्याज का हो सकता है (और यदि आप वेब पर आगे देखते हैं तो और भी तेज़ तरीके मौजूद हैं)। वही विकी पेज आसन्न मैट्रिसेस के बारे में बात करता है लेकिन आपके कोड को अन्य मैट्रिसेस के लिए भी काम करना चाहिए। आप मान सकते हैं कि सभी पूर्णांक होंगे, लेकिन ऐसा नहीं है कि वे सभी सकारात्मक हैं।

एक तेज़ एल्गोरिथम भी है लेकिन इसे समझना कठिन है। और क्रिश्चियन सिवर्स इसे (हास्केल में) लागू करने वाले पहले व्यक्ति थे।

इस प्रश्न में मैट्रिक्स सभी वर्ग और सममित सम आयाम के साथ हैं।

संदर्भ कार्यान्वयन (ध्यान दें कि यह सबसे धीमी संभव विधि का उपयोग कर रहा है)।

यहाँ श्री एक्सकोडर से कुछ उदाहरण अजगर कोड है।

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([[-1, 1, 1, -1, 0, 0, 1, -1], [1, 0, 1, 0, -1, 0, -1, -1], [1, 1, -1, 1, -1, -1, 0, -1], [-1, 0, 1, -1, -1, 1, -1, 0], [0, -1, -1, -1, -1, 0, 0, -1], [0, 0, -1, 1, 0, 0, 1, 1], [1, -1, 0, -1, 0, 1, 1, 0], [-1, -1, -1, 0, -1, 1, 0, 1]]))
4

M = [[1, 1, 0, 0, 0, 0, 0, 1, 0, 0], [1, 1, -1, 0, -1, 1, 1, 1, 0, -1], [0, -1, -1, -1, 0, -1, -1, 0, -1, 1], [0, 0, -1, 1, -1, 1, -1, 0, 1, -1], [0, -1, 0, -1, -1, -1, -1, 1, -1, 1], [0, 1, -1, 1, -1, 1, -1, -1, 1, -1], [0, 1, -1, -1, -1, -1, 1, 0, 0, 0], [1, 1, 0, 0, 1, -1, 0, 1, 1, -1], [0, 0, -1, 1, -1, 1, 0, 1, 1, 1], [0, -1, 1, -1, 1, -1, 0, -1, 1, 1]]

print(hafnian(M))
-13

M = [[-1, 0, -1, -1, 0, -1, 0, 1, -1, 0, 0, 0], [0, 0, 0, 0, 0, -1, 0, 1, -1, -1, -1, -1], [-1, 0, 0, 1, 0, 0, 0, 1, -1, 1, -1, 0], [-1, 0, 1, -1, 1, -1, -1, -1, 0, -1, -1, -1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, -1, 0], [-1, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, -1, 0, 1, 1, -1, -1, 0, 1, 0], [1, 1, 1, -1, 0, 1, -1, 1, -1, -1, -1, -1], [-1, -1, -1, 0, 0, 1, -1, -1, -1, 1, -1, 0], [0, -1, 1, -1, 1, 1, 0, -1, 1, -1, 1, 1], [0, -1, -1, -1, -1, 1, 1, -1, -1, 1, 0, -1], [0, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 1]]

print(hafnian(M))
13

M = [[-1, 1, 0, 1, 0, -1, 0, 0, -1, 1, -1, 1, 0, -1], [1, -1, 1, -1, 1, 1, -1, 0, -1, 1, 1, 0, 0, -1], [0, 1, 1, 1, -1, 1, -1, -1, 0, 0, -1, 0, -1, -1], [1, -1, 1, -1, 1, 0, 1, 1, -1, -1, 0, 0, 1, 1], [0, 1, -1, 1, 0, 1, 0, 1, -1, -1, 1, 1, 0, -1], [-1, 1, 1, 0, 1, 1, -1, 0, 1, -1, -1, -1, 1, -1], [0, -1, -1, 1, 0, -1, -1, -1, 0, 1, -1, 0, 1, -1], [0, 0, -1, 1, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1], [-1, -1, 0, -1, -1, 1, 0, 0, 1, 1, 0, 1, -1, 0], [1, 1, 0, -1, -1, -1, 1, -1, 1, 1, 1, 0, 1, 0], [-1, 1, -1, 0, 1, -1, -1, 0, 0, 1, -1, 0, -1, 0], [1, 0, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 1], [0, 0, -1, 1, 0, 1, 1, 0, -1, 1, -1, 1, 1, -1], [-1, -1, -1, 1, -1, -1, -1, 1, 0, 0, 0, 1, -1, -1]]

print(hafnian(M))
83

काम

आपको कोड लिखना चाहिए, जो मैट्रिक्स 2nद्वारा दिया गया 2nहै, इसके हाफ़ियनियन को आउटपुट करता है।

जैसा कि मुझे आपके कोड का परीक्षण करने की आवश्यकता होगी, यह उपयोगी होगा यदि आप मुझे अपने कोड के लिए एक इनपुट के रूप में मैट्रिक्स देने के लिए एक सरल तरीका दे सकते हैं, उदाहरण के लिए मानक से पढ़कर। मैं आपके कोड को यादृच्छिक रूप से चुने हुए मैट्रीस तत्वों के साथ परीक्षण करूंगा। {-1, 0, 1} से चयनित। इस तरह के परीक्षण का उद्देश्य हाफ़ियन को कम करने के लिए एक बहुत बड़ा मूल्य होगा।

आदर्श रूप से आपका कोड मैट्रिस में ठीक वैसे ही पढ़ा जा सकेगा जैसा कि मैंने उन्हें इस प्रश्न के उदाहरण में मानक से सीधे में दिया है। यह इनपुट [[1,-1],[-1,-1]]उदाहरण के लिए जैसा दिखेगा । यदि आप एक और इनपुट प्रारूप का उपयोग करना चाहते हैं, तो कृपया पूछें और मैं इसे समायोजित करने की पूरी कोशिश करूंगा।

स्कोर और संबंध

मैं आपके कोड को बढ़ते हुए आकार के बेतरतीब मैट्रीस पर परीक्षण करूँगा और पहली बार आपके कोड को मेरे कंप्यूटर पर 1 मिनट से अधिक समय तक रोक देगा। निष्पक्षता सुनिश्चित करने के लिए स्कोरिंग मैट्रीस सभी सबमिशन के अनुरूप होगा।

यदि दो लोगों को समान स्कोर मिलता है, तो विजेता वह है जो उस मूल्य के लिए सबसे तेज़ है n। यदि वे एक दूसरे के 1 सेकंड के भीतर हैं तो यह पहले पोस्ट किया गया एक है।

भाषाएं और पुस्तकालय

आप किसी भी उपलब्ध भाषा और लाइब्रेरियों का उपयोग कर सकते हैं, लेकिन हाफ़ियन की गणना करने के लिए कोई पूर्व-मौजूदा फ़ंक्शन नहीं। संभव होने पर, अपने कोड को चलाने में सक्षम होना अच्छा होगा, इसलिए कृपया अपने कोड को लिनक्स में कैसे चलाएं / संकलित करें, यदि संभव हो तो पूर्ण विवरण शामिल करें। `

माई मशीन द टाइमिंग को मेरी 64-बिट मशीन पर चलाया जाएगा। यह 8GB RAM, AMD FX-8350 Eight-Core Processor और Radeon HD 4250 के साथ एक मानक ubuntu स्थापित है। इसका मतलब यह भी है कि मुझे आपका कोड चलाने में सक्षम होना चाहिए।

अधिक भाषाओं में उत्तर के लिए कॉल करें

अपनी पसंदीदा सुपर फास्ट प्रोग्रामिंग भाषा में उत्तर प्राप्त करना बहुत अच्छा होगा। चीजों को शुरू करने के लिए, फोरट्रान , निम और जंग के बारे में कैसे ?

लीडरबोर्ड

  • C ++ का उपयोग करके 52 मील । 30 सेकंड।
  • सी का उपयोग करके ngn द्वारा 50 । 50 सेकंड।
  • 46 ईसाइयों द्वारा हास्केल का उपयोग करके । 40 सेकंड।
  • 40 मील की दूरी पर पायथन 2 + pypy का उपयोग करके । 41 सेकंड।
  • पायथन 3 + pypy का उपयोग करके ngn द्वारा 34 । 29 सेकंड।
  • 28 डेनिस द्वारा पायथन 3 का उपयोग कर । 35 सेकंड। (Pypy धीमा है)

क्या मैट्रिक्स प्रविष्टियों के पूर्ण मूल्यों के लिए एक सीमा है? क्या हम एक फ्लोटिंग पॉइंट सन्निकटन लौटा सकते हैं? क्या हमें मनमाने ढंग से सटीक पूर्णांक का उपयोग करना है?
डेनिस

@ डेनिस व्यवहार में मैं परीक्षण करने के लिए केवल -1,0,1 का उपयोग करेगा (यादृच्छिक पर चुना गया)। मैं नहीं चाहता कि यह एक बड़ी अंतर चुनौती हो। सभी ईमानदारी में मुझे नहीं पता कि अगर हम कोड को चलाने के लिए बहुत धीमी गति से दौड़ते हैं तो 64 बिट्स की सीमाएं टकराएंगी, लेकिन मेरा अनुमान है कि हम ऐसा नहीं करेंगे। वर्तमान में हम कहीं नहीं हैं।

यदि प्रविष्टियाँ -1,0,1 तक सीमित हैं , तो इस प्रश्न पर उल्लेख किया जाना चाहिए। क्या हमारे कोड को अन्य मैट्रिक्स के लिए बिल्कुल काम करना है?
डेनिस

@ डेनिस एक पुराना संस्करण कहता था, लेकिन मैंने उस पर लिखा होगा। अगर कोड -1,0,1 प्रविष्टियों के लिए विशेष नहीं था, तो मैं इसे पसंद करूंगा, लेकिन मुझे लगता है कि मैं इसे रोक नहीं सकता।

क्या आपके पास अधिक परीक्षण मामले हैं? शायद बड़े n के लिए ?
मील

जवाबों:


14

हास्केल

import Control.Parallel.Strategies
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector as VB

type Poly = V.Vector Int

type Matrix = VB.Vector ( VB.Vector Poly )

constpoly :: Int -> Int -> Poly
constpoly n c = V.generate (n+1) (\i -> if i==0 then c else 0)

add :: Poly -> Poly -> Poly
add = V.zipWith (+)

shiftmult :: Poly -> Poly -> Poly
shiftmult a b = V.generate (V.length a) 
                           (\i -> sum [ a!j * b!(i-1-j) | j<-[0..i-1] ])
  where (!) = V.unsafeIndex

x :: Matrix -> Int -> Int -> Int -> Poly -> Int
x  _    0  _ m p = m * V.last p
x mat n c m p =
  let mat' = VB.generate (2*n-2) $ \i ->
             VB.generate i       $ \j ->
                 shiftmult (mat!(2*n-1)!i) (mat!(2*n-2)!j) `add`
                 shiftmult (mat!(2*n-1)!j) (mat!(2*n-2)!i) `add`
                 (mat!i!j)
      p' = p `add` shiftmult (mat!(2*n-1)!(2*n-2)) p
      (!) = VB.unsafeIndex
      r = if c>0 then parTuple2 rseq rseq else r0
      (a,b) = (x mat (n-1) (c-1) m p, x mat' (n-1) (c-1) (-m) p')
              `using` r
  in a+b

haf :: [[Int]] -> Int
haf m = let n=length m `div` 2
        in x (VB.fromList $ map (VB.fromList . map (constpoly n)) m) 
             n  5  ((-1)^n)  (constpoly n 1) 

main = getContents >>= print . haf . read

यह एंड्रियास ब्योर्क्लकुंड के एल्गोरिथ्म 2 के एक बदलाव को लागू करता है : रायसर के रूप में फास्ट के रूप में सही मिलान की गिनती

ghcसंकलन समय विकल्पों के साथ संकलन का उपयोग करें -O3 -threadedऔर +RTS -Nसमानांतरकरण के लिए रन समय विकल्प का उपयोग करें । स्टड से इनपुट लेता है।


2
शायद ध्यान दें कि parallelऔर vectorस्थापित किया जाना चाहिए?
H.PWiz

@ H.PWiz किसी ने भी यहां शिकायत नहीं की , लेकिन यकीन है, यह ध्यान देने योग्य नहीं है। अच्छा, अब तुमने किया।
क्रिश्चियन सेवर्स

@ChristianSievers मुझे नहीं लगता कि वे शिकायत कर रहे हैं। ओपी हास्केल से परिचित नहीं हो सकता है, इसलिए स्पष्ट रूप से बताते हुए कि कोड को स्थापित करने में सक्षम होने के लिए क्या स्थापित किया जाना चाहिए एक अच्छा विचार है।
डेनिस

@ डेनिस का मतलब यह नहीं था कि "आपने शिकायत की" लेकिन "आपने इसे नोट किया"। और मैं एक नकारात्मक बात के रूप में शिकायत करने के बारे में नहीं सोचा था। ओपी उसी तरह का है जिस चुनौती से मैं जुड़ा था, इसलिए कोई समस्या नहीं होनी चाहिए।
क्रिश्चियन सेवर्स

TIO पर N = 40 7.5 सेकंड में ... यार, यह तेज़ है!
डेनिस


6

C ++ (gcc)

#define T(x) ((x)*((x)-1)/2)
#define S 1
#define J (1<<S)
#define TYPE int

#include <iostream>
#include <vector>
#include <string>
#include <pthread.h>

using namespace std;

struct H {
    int s, w, t;
    TYPE *b, *g;
};

void *solve(void *a);
void hafnian(TYPE *b, int s, TYPE *g, int w, int t);

int n, m, ti = 0;
TYPE r[J] = {0};
pthread_t pool[J];

int main(void) {
    vector<int> a;
    string s;
    getline(cin, s);

    for (int i = 0; i < s.size(); i++)
        if (s[i] == '0' || s[i] == '1')
            a.push_back((s[i-1] == '-' ? -1 : 1)*(s[i] - '0'));

    for (n = 1; 4*n*n < a.size(); n++);
    m = n+1;

    TYPE z[T(2*n)*m] = {0}, g[m] = {0};

    for (int j = 1; j < 2*n; j++)
        for (int k = 0; k < j; k++)
            z[(T(j)+k)*m] = a[j*2*n+k];
    g[0] = 1;

    hafnian(z, 2*n, g, 1, -1);

    TYPE h = 0;
    for (int t = 0; t < ti; t++) {
        pthread_join(pool[t], NULL);
        h += r[t];
    }

    cout << h << endl;

    return 0;
}

void *solve(void *a) {
    H *p = reinterpret_cast<H*>(a);
    hafnian(p->b, p->s, p->g, p->w, p->t);
    delete[] p->b;
    delete[] p->g;
    delete p;
    return NULL;
}

void hafnian(TYPE *b, int s, TYPE *g, int w, int t) {
    if (t == -1 && (n < S || s/2 == n-S)) {
        H *p = new H;
        TYPE *c = new TYPE[T(s)*m], *e = new TYPE[m];
        copy(b, b+T(s)*m, c);
        copy(g, g+m, e);
        p->b = c;
        p->s = s;
        p->g = e;
        p->w = w;
        p->t = ti;
        pthread_create(pool+ti, NULL, solve, p);
        ti++;
    }
    else if (s > 0) {
        TYPE c[T(s-2)*m], e[m];
        copy(b, b+T(s-2)*m, c);
        hafnian(c, s-2, g, -w, t);
        copy(g, g+m, e);

        for (int u = 0; u < n; u++) {
            TYPE *d = e+u+1,
                  p = g[u], *x = b+(T(s)-1)*m;
            for (int v = 0; v < n-u; v++)
                d[v] += p*x[v];
        }

        for (int j = 1; j < s-2; j++)
            for (int k = 0; k < j; k++)
                for (int u = 0; u < n; u++) {
                    TYPE *d = c+(T(j)+k)*m+u+1,
                          p = b[(T(s-2)+j)*m+u], *x = b+(T(s-1)+k)*m,
                          q = b[(T(s-2)+k)*m+u], *y = b+(T(s-1)+j)*m;
                    for (int v = 0; v < n-u; v++)
                        d[v] += p*x[v] + q*y[v];
                }

        hafnian(c, s-2, e, w, t);
    }
    else
        r[t] += w*g[n];
}

इसे ऑनलाइन आज़माएं! (13s के लिए n = 24)

मेरे अन्य पोस्ट में तेजी से पायथन कार्यान्वयन के आधार पर । #define S 3अपने 8-कोर मशीन पर दूसरी पंक्ति को संपादित करें और इसके साथ संकलित करें g++ -pthread -march=native -O2 -ftree-vectorize

काम को आधे में विभाजित करता है, इसलिए मूल्य का Sहोना चाहिए log2(#threads)। प्रकार आसानी से बदला जा सकता है के बीच int, long, float, और doubleके मूल्य को संशोधित करके #define TYPE


यह अब तक का प्रमुख उत्तर है। आपका कोड वास्तव में इनपुट में नहीं पढ़ा है क्योंकि यह रिक्त स्थान के साथ सामना नहीं कर सकता है। मुझे करना था जैसेtr -d \ < matrix52.txt > matrix52s.txt

@Lembik क्षमा करें, केवल इसका आकार 24 के स्पेसलेस मैट्रिक्स के विरुद्ध उपयोग किया गया था। हालांकि अभी रिक्त स्थान के साथ काम करने के लिए निश्चित है।
मील

4

अजगर ३

यह haf (A) को संस्मरण योग के रूप में गणना करता है (A [i] [j] * haf (A बिना पंक्तियों और cols i और j) के।

#!/usr/bin/env python3
import json,sys
a=json.loads(sys.stdin.read())
n=len(a)//2
b={0:1}
def haf(x):
 if x not in b:
  i=0
  while not x&(1<<i):i+=1
  x1=x&~(1<<i)
  b[x]=sum(a[i][j]*haf(x1&~(1<<j))for j in range(2*n)if x1&(1<<j)and a[i][j])
 return b[x]
print(haf((1<<2*n)-1))

3

सी

Andreas Björklund के पेपर का एक और इम्प्लान्ट है , जिसे समझना बहुत आसान है अगर आप क्रिश्चियन सिवर्स के हास्केल कोड को भी देखें । पुनरावृत्ति के पहले कुछ स्तरों के लिए, यह उपलब्ध सीपीयू पर गोल-रॉबिन थ्रेड वितरित करता है। पुनरावृत्ति का अंतिम स्तर, जो आधे चालान के लिए जिम्मेदार है, हाथ से अनुकूलित है।

के साथ संकलन gcc -O3 -pthread -march=native:; धन्यवाद @ एक 2x गति के लिए डेनिस

n = 24 में 24 TIO पर

#define _GNU_SOURCE
#include<sched.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<unistd.h>
#include<pthread.h>
#define W while
#define R return
#define S static
#define U (1<<31)
#define T(i)((i)*((i)-1)/2)
typedef int I;typedef long L;typedef char C;typedef void V;
I n,ncpu,icpu;
S V f(I*x,I*y,I*z){I i=n,*z1=z+n;W(i){I s=0,*x2=x,*y2=y+--i;W(y2>=y)s+=*x2++**y2--;*z1--+=s;}}
typedef struct{I m;V*a;V*p;pthread_barrier_t*bar;I r;}A;S V*(h1)(V*);
I h(I m,I a[][n+1],I*p){
 m-=2;I i,j,k=0,u=T(m),v=u+m,b[u][n+1],q[n+1];
 if(!m){I*x=a[v+m],*y=p+n-1,s=0;W(y>=p)s-=*x++**y--;R s;}
 memcpy(b,a,sizeof(b));memcpy(q,p,sizeof(q));f(a[v+m],p,q);
 for(i=1;i<m;i++)for(j=0;j<i;j++){f(a[u+i],a[v+j],b[k]);f(a[u+j],a[v+i],b[k]);k++;}
 if(2*n-m>8)R h(m,a,p)-h(m,b,q);
 pthread_barrier_t bar;pthread_barrier_init(&bar,0,2);pthread_t th;
 cpu_set_t cpus;CPU_ZERO(&cpus);CPU_SET(icpu++%ncpu,&cpus);
 pthread_attr_t attr;pthread_attr_init(&attr);
 pthread_attr_setaffinity_np(&attr,sizeof(cpu_set_t),&cpus);
 A arg={m,a,p,&bar};pthread_create(&th,&attr,h1,&arg);
 I r=h(m,b,q);pthread_barrier_wait(&bar);pthread_join(th,0);pthread_barrier_destroy(&bar);
 R arg.r-r;
}
S V*h1(V*x0){A*x=(A*)x0;x->r=h(x->m,x->a,x->p);pthread_barrier_wait(x->bar);R 0;}
I main(){
 ncpu=sysconf(_SC_NPROCESSORS_ONLN);
 S C s[200000];I i=0,j=0,k,l=0;W((k=read(0,s+l,sizeof(s)-l))>0)l+=k;
 n=1;W(s[i]!=']')n+=s[i++]==',';n/=2;
 I a[T(2*n)][n+1];memset(a,0,sizeof(a));k=0;
 for(i=0;i<2*n;i++)for(j=0;j<2*n;j++){
  W(s[k]!='-'&&(s[k]<'0'||s[k]>'9'))k++;
  I v=0,m=s[k]=='-';k+=m;W(k<l&&('0'<=s[k]&&s[k]<='9'))v=10*v+s[k++]-'0';
  if(i>j)*a[T(i)+j]=v*(1-2*m);
 }
 I p[n+1];memset(p,0,sizeof(p));*p=1;
 printf("%d\n",(1-2*(n&1))*h(2*n,a,p));
 R 0;
}

कलन विधि:

मैट्रिक्स, जो सममित है, को निचले-बाएं त्रिकोणीय रूप में संग्रहीत किया जाता है। त्रिकोण सूचकांक i,jरेखीय सूचकांक के अनुरूप हैं T(max(i,j))+min(i,j)जहां के Tलिए एक मैक्रो है i*(i-1)/2। मैट्रिक्स तत्व डिग्री के बहुपद हैं n। एक बहुपद को गुणांक के एक सरणी के रूप में निरूपित किया जाता है जिसे निरंतर शब्द ( p[0]) से x n के गुणांक ( p[n]) में क्रमबद्ध किया जाता है । शुरुआती -1,0,1 मैट्रिक्स मूल्य पहले कॉन्स्टेंट पॉलीनोमियल में परिवर्तित हो जाते हैं।

हम दो तर्कों के साथ एक पुनरावर्ती कदम करते हैं: aबहुपद के अर्ध-मैट्रिक्स (अर्थात त्रिकोण) और एक अलग बहुपद p(कागज में बीटा के रूप में संदर्भित)। हम आकार की mसमस्या (शुरू में m=2*n) को पुन: आकार की दो समस्याओं को कम कर देते हैं m-2और उनके हफ़नियों के अंतर को वापस करते हैं। उनमें से एक aअपनी पिछली दो पंक्तियों के बिना समान का उपयोग करना है , और बहुत ही समान है p। एक और त्रिभुज का उपयोग करना है b[i][j] = a[i][j] + shmul(a[m-1][i],a[m-2][j]) + shmul(a[m-1][j],a[m-2][i])(जहां shmulबहुपद पर शिफ्ट-गुणा ऑपरेशन है - यह बहुपदीय उत्पाद हमेशा की तरह है, इसके अलावा चर "x" से गुणा किया जाता है; x ^ n से अधिक शक्तियां नजरअंदाज की जाती हैं), और अलग बहुपद q = p + shmul(p,a[m-1][m-2])। जब पुनरावर्तन आकार -० से टकराता है a, तो हम p का मुख्य गुणांक लौटाते हैं p[n]:।

फ़ंक्शन में शिफ्ट-एंड-मल्टिपल ऑपरेशन कार्यान्वित किया जाता है f(x,y,z)। यह zजगह में संशोधन करता है। धीरे-धीरे बोलना, यह करता है z += shmul(x,y)। यह सबसे महत्वपूर्ण प्रदर्शन वाला हिस्सा लगता है।

पुनरावृत्ति समाप्त होने के बाद, हमें (-1) n से गुणा करके परिणाम के संकेत को ठीक करना होगा ।


क्या आप उस इनपुट का स्पष्ट उदाहरण दिखा सकते हैं जिसे आपका कोड स्वीकार करता है? 2 बाय 2 मैट्रिक्स के लिए कहें। इसके अलावा, आपको लगता है कि आपने अपना कोड गोल्फ कर लिया है! (यह एक सबसे तेज़-कोड चुनौती है, न कि गोल्फ चुनौती।)

@Lembik रिकॉर्ड के लिए, जैसा कि मैंने चैट में कहा है, इनपुट उदाहरण के रूप में एक ही प्रारूप में है - json (वास्तव में, यह केवल संख्या पढ़ता है और n = sqrt (len (इनपुट)) / 2) का उपयोग करता है। मैं आमतौर पर शॉर्ट कोड लिखता हूं, तब भी जब गोल्फ की आवश्यकता नहीं है।
नागिन

इस नए कोड का सबसे बड़ा आकार मैट्रिक्स क्या है?

1
-march=nativeयहाँ एक बड़ा फर्क पड़ेगा। कम से कम TIO पर, यह लगभग दीवार के समय को आधे में काट देता है।
डेनिस

1
इसके अलावा, कम से कम TIO पर, gcc द्वारा उत्पादित निष्पादन योग्य और भी तेज होगा।
डेनिस

3

अजगर

यह उल्लेखित कागज़ से अल्गोरिथम 2 का एक बहुत ही आगे-आगे, संदर्भ कार्यान्वयन है । केवल परिवर्तन केवल के वर्तमान मूल्य रखने के लिए थे बी , के मूल्यों छोड़ने β केवल अपडेट करके जी जब मैंएक्स , और छोटा कर दिया बहुपद गुणा केवल डिग्री करने के लिए मान की गणना के द्वारा एन

from itertools import chain,combinations

def powerset(s):
    return chain.from_iterable(combinations(s, k) for k in range(len(s)+1))

def padd(a, b):
    return [a[i]+b[i] for i in range(len(a))]

def pmul(a, b):
    n = len(a)
    c = [0]*n
    for i in range(n):
        for j in range(n):
            if i+j < n:
                c[i+j] += a[i]*b[j]
    return c

def hafnian(m):
    n = len(m) / 2
    z = [[[c]+[0]*n for c in r] for r in m]
    h = 0
    for x in powerset(range(1, n+1)):
        b = z
        g = [1] + [0]*n
        for i in range(1, n+1):
            if i in x:
                g = pmul(g, [1] + b[0][1][:n])
                b = [[padd(b[j+2][k+2], [0] + padd(pmul(b[0][j+2], b[1][k+2]), pmul(b[0][k+2], b[1][j+2]))[:n]) if j != k else 0 for k in range(2*n-2*i)] for j in range(2*n-2*i)]
            else:
                b = [r[2:] for r in b[2:]]
        h += (-1)**(n - len(x)) * g[n]
    return h

इसे ऑनलाइन आज़माएं!

यहाँ कुछ आसान अनुकूलन के साथ एक तेज़ संस्करण है।

def hafnian(m):
  n = len(m)/2
  z = [[0]*(n+1) for _ in range(n*(2*n-1))]
  for j in range(1, 2*n):
    for k in range(j):
      z[j*(j-1)/2+k][0] = m[j][k]
  return solve(z, 2*n, 1, [1] + [0]*n, n)

def solve(b, s, w, g, n):
  if s == 0:
    return w*g[n]
  c = [b[(j+1)*(j+2)/2+k+2][:] for j in range(1, s-2) for k in range(j)]
  h = solve(c, s-2, -w, g, n)
  e = g[:]
  for u in range(n):
    for v in range(n-u):
      e[u+v+1] += g[u]*b[0][v]
  for j in range(1, s-2):
    for k in range(j):
      for u in range(n):
        for v in range(n-u):
          c[j*(j-1)/2+k][u+v+1] += b[(j+1)*(j+2)/2][u]*b[(k+1)*(k+2)/2+1][v] + b[(k+1)*(k+2)/2][u]*b[(j+1)*(j+2)/2+1][v]
  return h + solve(c, s-2, w, e, n)

इसे ऑनलाइन आज़माएं!

अतिरिक्त मनोरंजन के लिए, यहां जे में एक संदर्भ कार्यान्वयन है।


यह सभी सूची समझ से और विकर्ण के समतुल्य समान मूल्यों की गणना करने से बहुत धीमा है, इसलिए इसे बेंचमार्क करने की कोई आवश्यकता नहीं है।
मील

बड़िया!

बहुत अच्छा! मैंने सिम्पी के साथ एक ऐसी चीज़ की कोशिश की, जो शॉकली धीमी थी और छोटे उदाहरणों के लिए सही होने के बावजूद, लंबे समय के बाद लौटी - 24 * 24 मैट्रिक्स के लिए एक गलत परिणाम। मुझे नहीं पता कि वहां क्या चल रहा है। - एल्गोरिथम 2 के ऊपर के विवरण के अनुसार, बहुपद गुणन का मतलब पहले से ही छोटा है।
क्रिश्चियन सेवर्स

2
में pmul, का उपयोग करें for j in range(n-i):और से बचेंif
क्रिश्चियन सेवर्स

1
@ लेम्बिक यह पूरे मैट्रिक्स की गणना करता है; लगभग दो के एक कारक के j != kसाथ के लिए बदलें j < k। यह दूसरे मामले में एक सबमेट्रिक्स को कॉपी करता है जिसे पहले दो पंक्तियों और स्तंभों के बजाय अंतिम दो को संभालने और हटाने पर टाला जा सकता है। और जब यह संगणना करता है x={1,2,4}और बाद में इसके साथ x={1,2,4,6}अपनी गणना को दोहराता है i=5। मैंने पहले लूपिंग के साथ दो बाहरी छोरों की संरचना को बदल दिया iऔर फिर पुनरावर्ती रूप से ग्रहण किया i in Xऔर i not in X। - BTW, अन्य धीमी कार्यक्रमों की तुलना में आवश्यक समय के विकास को देखना दिलचस्प हो सकता है।
क्रिश्चियन सिवर्स

1

सप्टक

यह मूल रूप से डेनिस की प्रविष्टि की एक प्रति है , लेकिन ऑक्टेव के लिए अनुकूलित है। मुख्य अनुकूलन पूर्ण इनपुट मैट्रिक्स (और इसके स्थानान्तरण) का उपयोग करके किया जाता है और कम मैट्रिक्स बनाने के बजाय केवल मैट्रिक्स सूचकांकों का उपयोग करके पुनरावृत्ति होती है।

मुख्य लाभ मेट्रिसेस की नकल को कम करता है। हालांकि ऑक्टेव में संकेत / संदर्भ और मूल्यों के बीच अंतर नहीं है और कार्यात्मक रूप से केवल पास-बाय-वैल्यू है, यह पर्दे के पीछे एक अलग कहानी है। वहां, कॉपी-ऑन-राइट (आलसी कॉपी) का उपयोग किया जाता है। इसका मतलब है कि, कोड के लिए a=1;b=a;b=b+1, चर bको अंतिम विवरण में एक नए स्थान पर कॉपी किया जाता है, जब इसे बदल दिया जाता है। चूंकि matinऔर matranspकभी नहीं बदले जाते हैं, वे कभी भी नकल नहीं करेंगे। नुकसान यह है कि फ़ंक्शन सही सूचकांकों की गणना करने में अधिक समय खर्च करता है। मुझे इसे अनुकूलित करने के लिए संख्यात्मक और तार्किक सूचकांकों के बीच अलग-अलग बदलावों की कोशिश करनी पड़ सकती है।

महत्वपूर्ण नोट: इनपुट मैट्रिक्स होना चाहिए int32! फ़ंक्शन को फ़ाइल नामक फ़ाइल में सहेजेंhaf.m

function h=haf(matin,indices,matransp,transp)

    if nargin-4
        indices=int32(1:length(matin));
        matransp=matin';
        transp=false;
    end
    if(transp)
        matrix=matransp;
    else
        matrix=matin;
    end
    ind1=indices(1);
    n=length(indices);
    if n==2
        h=matrix(ind1,indices(2));
        return
    end
    h=0*matrix(1); 
    for j=1:(n-1)
        indj=indices(j+1);
        k=matrix(ind1,indj);
        if logical(k)
            indicestemp=true(n,1);
            indicestemp(1:j:j+1)=false;
            h=h+k.*haf(matin,indices(indicestemp),matransp,~transp);
        end
    end
end

उदाहरण परीक्षण स्क्रिप्ट:

matrix = int32([0 0 1 -1 1 0 -1 -1 -1 0 -1 1 0 1 1 0 0 1 0 0 1 0 1 1;0 0 1 0 0 -1 -1 -1 -1 0 1 1 1 1 0 -1 -1 0 0 1 1 -1 0 0;-1 -1 0 1 0 1 -1 1 -1 1 0 0 1 -1 0 0 0 -1 0 -1 1 0 0 0;1 0 -1 0 1 1 0 1 1 0 0 0 1 0 0 0 1 -1 -1 -1 -1 1 0 -1;-1 0 0 -1 0 0 1 -1 0 1 -1 -1 -1 1 1 0 1 1 1 0 -1 1 -1 -1;0 1 -1 -1 0 0 1 -1 -1 -1 0 -1 1 0 0 0 -1 0 0 1 0 0 0 -1;1 1 1 0 -1 -1 0 -1 -1 0 1 1 -1 0 1 -1 0 0 1 -1 0 0 0 -1;1 1 -1 -1 1 1 1 0 0 1 0 1 0 0 0 0 1 0 1 0 -1 1 0 0;1 1 1 -1 0 1 1 0 0 -1 1 -1 1 1 1 0 -1 -1 -1 -1 0 1 1 -1;0 0 -1 0 -1 1 0 -1 1 0 1 0 0 0 0 0 1 -1 0 0 0 1 -1 -1;1 -1 0 0 1 0 -1 0 -1 -1 0 0 1 0 0 -1 0 -1 -1 -1 -1 -1 1 -1;-1 -1 0 0 1 1 -1 -1 1 0 0 0 -1 0 0 -1 0 -1 -1 0 1 -1 0 0;0 -1 -1 -1 1 -1 1 0 -1 0 -1 1 0 1 -1 -1 1 -1 1 0 1 -1 1 -1;-1 -1 1 0 -1 0 0 0 -1 0 0 0 -1 0 0 -1 1 -1 -1 0 1 0 -1 -1;-1 0 0 0 -1 0 -1 0 -1 0 0 0 1 0 0 1 1 1 1 -1 -1 0 -1 -1;0 1 0 0 0 0 1 0 0 0 1 1 1 1 -1 0 0 1 -1 -1 -1 0 -1 -1;0 1 0 -1 -1 1 0 -1 1 -1 0 0 -1 -1 -1 0 0 -1 1 0 0 -1 -1 1;-1 0 1 1 -1 0 0 0 1 1 1 1 1 1 -1 -1 1 0 1 1 -1 -1 -1 1;0 0 0 1 -1 0 -1 -1 1 0 1 1 -1 1 -1 1 -1 -1 0 1 1 0 0 -1;0 -1 1 1 0 -1 1 0 1 0 1 0 0 0 1 1 0 -1 -1 0 0 0 1 0;-1 -1 -1 1 1 0 0 1 0 0 1 -1 -1 -1 1 1 0 1 -1 0 0 0 0 0;0 1 0 -1 -1 0 0 -1 -1 -1 1 1 1 0 0 0 1 1 0 0 0 0 1 0;-1 0 0 0 1 0 0 0 -1 1 -1 0 -1 1 1 1 1 1 0 -1 0 -1 0 1;-1 0 0 1 1 1 1 0 1 1 1 0 1 1 1 1 -1 -1 1 0 0 0 -1 0])

tic
i=1;
while(toc<60)
    tic
    haf(matrix(1:i,1:i));
    i=i+1;
end

मैंने TIO और MATLAB का उपयोग करके इसे आज़माया है (मैंने वास्तव में कभी भी स्थापित नहीं किया है)। मुझे लगता है कि यह काम करना उतना ही सरल है जितना कि sudo apt-get install octave। कमांड octaveऑक्टेव GUI को लोड करेगा। यदि यह इससे अधिक जटिल है, तो मैं इस उत्तर को तब तक हटा दूंगा, जब तक कि मैं अधिक विस्तृत इंस्टॉलेशन निर्देश प्रदान नहीं कर देता।


0

हाल ही में एंड्रियास बीजेर्कलंड, ब्रजेश गुप्त और स्वयं ने जटिल मैट्रिसेस के हाफियंस के लिए एक नया एल्गोरिथ्म प्रकाशित किया: https://arxiv.org/pdf/1805.12498.pdf । N \ n n मैट्रिक्स के लिए यह n ^ 3 2 ^ {n / 2} की तरह होता है।

अगर मैं सही ढंग से एंड्रियास के मूल एल्गोरिथ्म https://arxiv.org/pdf/1107.4466.pdf से समझता हूं, तो यह n ^ 4 2 ^ {n / 2} या n ^ 3 लॉग (n) 2 ^ {n / 2} की तरह है। यदि आपने फूरियर का उपयोग बहुपद गुणन करने के लिए किया है।
हमारा एल्गोरिथ्म विशेष रूप से जटिल मैट्रिस के लिए taylored है, इसलिए यह उतना तेज़ नहीं होगा जितना कि {-1,0,1} मैट्रिस के लिए यहां विकसित किया गया है। हालांकि मुझे आश्चर्य है कि यदि कोई हमारे कार्यान्वयन में सुधार करने के लिए आपके द्वारा उपयोग किए गए कुछ ट्रिक्स का उपयोग कर सकता है? अगर लोग दिलचस्पी रखते हैं तो मैं यह देखना चाहूंगा कि पूर्णांक के बजाय जटिल संख्याओं को देखते हुए उनका कार्यान्वयन कैसे होता है। अंत में, किसी भी टिप्पणी, आलोचना, सुधार, कीड़े, सुधार का हमारे भंडार https://github.com/XanaduAI/ffingu/ में स्वागत है।

चीयर्स!


साइट पर आपका स्वागत है! हालाँकि इस सवाल का जवाब कोड होना चाहिए। यह एक टिप्पणी के रूप में बेहतर होगा, (जो दुर्भाग्य से आपके पास बनाने के लिए प्रतिनिधि नहीं है)।
तदर्थ गार्फ हंटर

PPCG में आपका स्वागत है। हालांकि आपका जवाब ठीक टिप्पणी कर सकता है, साइट QA के लिए नहीं है। यह एक चुनौती स्थल है और एक चुनौती का जवाब कोड होना चाहिए और कुछ और का स्पष्टीकरण नहीं होना चाहिए। कृपया अपडेट करें या डिलीट करें (यदि आप नहीं करेंगे तो mods करेंगे)
मुहम्मद सलमान

ठीक है, कोड जीथब पर है, लेकिन मुझे लगता है कि इसे यहां कॉपी-पेस्ट करना बकवास है।
निकोलस कुसाडा

2
यदि यह एक उत्तर में फिट बैठता है, खासकर यदि आप लेखकों में से एक हैं, तो मुझे नहीं लगता कि एक उचित रूप से जिम्मेदार, प्रतिस्पर्धी समाधान पोस्ट करने में कुछ भी गलत है जो कहीं और प्रकाशित किया गया था।
डेनिस

इस साइट पर @ NicolásQuesada उत्तर यदि संभव हो तो स्व-निहित होना चाहिए, जिसका अर्थ है कि हमें आपका उत्तर / कोड देखने के लिए किसी अन्य साइट पर नहीं जाना चाहिए।
mbomb007
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.