Hankelable matrices की संख्या गिनें


12

पृष्ठभूमि

एक बाइनरी हैंकेल मैट्रिक्स एक मैट्रिक्स है जिसमें निरंतर तिरछा-विकर्ण (सकारात्मक ढलान विकर्ण) होता है जिसमें केवल 0एस और 1एस होते हैं। जैसे 5x5 बाइनरी हैंकेल मैट्रिक्स दिखता है

a b c d e
b c d e f
c d e f g
d e f g h
e f g h i

जहां a, b, c, d, e, f, g, h, iया तो 0या 1

चलो एक मैट्रिक्स को परिभाषित एम के रूप में Hankelable अगर वहाँ पंक्तियों और के कॉलम के क्रम का क्रमपरिवर्तन है एम ताकि एम एक हेंकल मैट्रिक्स है। इसका मतलब यह है कि एक पंक्तियों के क्रम में एक क्रमपरिवर्तन लागू कर सकता है और स्तंभों के लिए संभवतः एक अलग हो सकता है।

चुनौती

चुनौती गिनती करने के लिए कितने है Hankelable n द्वारा nसभी के लिए कर रहे हैं मैट्रिक्स nसंभव के रूप में बड़े एक मूल्य के रूप में करने के लिए।

उत्पादन

1 से ऊपर के प्रत्येक पूर्णांक n के लिए, प्रविष्टियों के साथ मेट्रिसेस द्वारा हैंकेबल की संख्या को आउटपुट करें जो या हैं ।nn01

के लिए n = 1,2,3,4,5जवाब होना चाहिए 2,12,230,12076,1446672। (इन का उत्पादन करने के लिए कोड के लिए आभार।)

समय सीमा

मैं आपके कोड को अपनी मशीन पर चलाऊंगा और 1 मिनट के बाद बंद कर दूंगा। वह कोड जो n जवाबों के सबसे बड़े मूल्य तक सही उत्तरों को आउटपुट करता है। समय सीमा सब कुछ n = 1के लिए सबसे बड़ा मूल्य है nजिसके लिए आप एक जवाब देते हैं।

विजेता शनिवार 18 अप्रैल के अंत तक सबसे अच्छा जवाब होगा।

टाई ब्रेकर

कुछ अधिकतम के लिए एक टाई के मामले में nमैं समय देगा कि आउटपुट को कितना समय लगता है n+1और सबसे तेज एक जीत होती है। इस मामले में कि वे एक ही समय में एक दूसरे तक n+1, पहले सबमिशन जीतते हैं।

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

आप किसी भी भाषा का उपयोग कर सकते हैं जिसमें एक स्वतंत्र रूप से उपलब्ध संकलक / दुभाषिया / आदि है। लिनक्स और किसी भी पुस्तकालय के लिए जो लिनक्स के लिए भी स्वतंत्र रूप से उपलब्ध हैं।

मेरी मशीन

टाइमिंग को मेरी मशीन पर चलाया जाएगा। यह Asus M5A78L-M / USB3 मदरबोर्ड (सॉकेट AM3 +, 8GB DDR3) पर AMD FX-8350 आठ-कोर प्रोसेसर पर एक मानक ubuntu स्थापित है। इसका मतलब यह भी है कि मुझे आपका कोड चलाने में सक्षम होना चाहिए। परिणामस्वरूप, केवल आसानी से उपलब्ध मुफ्त सॉफ़्टवेयर का उपयोग करें और कृपया अपने कोड को संकलित करने और चलाने के लिए पूर्ण निर्देश शामिल करें।

टिप्पणियाँ

मैं n मेट्रिसेस द्वारा सभी n पर पुनरावृत्ति करने और यह पता लगाने की कोशिश कर रहा हूं कि क्या प्रत्येक के पास मेरे द्वारा वर्णित संपत्ति है। पहला, बहुत अधिक हैं और दूसरा, इस खोज को करने का कोई त्वरित तरीका नहीं है

अब तक की प्रमुख प्रविष्टियाँ

  • n = 8 पीटर टेलर द्वारा। जावा
  • n = 5 द्वारा orlp। अजगर

4
मैं वास्तव में "हंकेलेबल" शब्द का आनंद लेता हूं।
एलेक्स ए।

3
के लिए n=6कुल है 260357434। मुझे लगता है कि सीपीयू समय की तुलना में स्मृति दबाव एक बड़ा मुद्दा है।
पीटर टेलर

यह एक भयानक सवाल है। मुझे पूरी तरह से बेवकूफ बनाया गया है।
अलेक्जेंडर-ब्रेट

जवाबों:


7

जावा (n = 8)

import java.util.*;
import java.util.concurrent.*;

public class HankelCombinatorics {
    public static final int NUM_THREADS = 8;

    private static final int[] FACT = new int[13];
    static {
        FACT[0] = 1;
        for (int i = 1; i < FACT.length; i++) FACT[i] = i * FACT[i-1];
    }

    public static void main(String[] args) {
        long prevElapsed = 0, start = System.nanoTime();
        for (int i = 1; i < 12; i++) {
            long count = count(i), elapsed = System.nanoTime() - start;
            System.out.format("%d in %dms, total elapsed %dms\n", count, (elapsed - prevElapsed) / 1000000, elapsed / 1000000);
            prevElapsed = elapsed;
        }
    }

    @SuppressWarnings("unchecked")
    private static long count(int n) {
        int[][] perms = new int[FACT[n]][];
        genPermsInner(0, 0, new int[n], perms, 0);

        // We partition by canonical representation of the row sum multiset, discarding any with a density > 50%.
        Map<CanonicalMatrix, Map<CanonicalMatrix, Integer>> part = new HashMap<CanonicalMatrix, Map<CanonicalMatrix, Integer>>();
        for (int m = 0; m < 1 << (2*n-1); m++) {
            int density = 0;
            int[] key = new int[n];
            for (int i = 0; i < n; i++) {
                key[i] = Integer.bitCount((m >> i) & ((1 << n) - 1));
                density += key[i];
            }
            if (2 * density <= n * n) {
                CanonicalMatrix _key = new CanonicalMatrix(key);
                Map<CanonicalMatrix, Integer> map = part.get(_key);
                if (map == null) part.put(_key, map = new HashMap<CanonicalMatrix, Integer>());
                map.put(new CanonicalMatrix(m, perms[0]), m);
            }
        }

        List<Job> jobs = new ArrayList<Job>();
        ExecutorService pool = Executors.newFixedThreadPool(NUM_THREADS);

        for (Map.Entry<CanonicalMatrix, Map<CanonicalMatrix, Integer>> e : part.entrySet()) {
            Job job = new Job(n, perms, e.getKey().sum() << 1 == n * n ? 0 : 1, e.getValue());
            jobs.add(job);
            pool.execute(job);
        }

        pool.shutdown();
        try {
            pool.awaitTermination(1, TimeUnit.DAYS); // i.e. until it's finished - inaccurate results are useless
        }
        catch (InterruptedException ie) {
            throw new IllegalStateException(ie);
        }

        long total = 0;
        for (Job job : jobs) total += job.subtotal;
        return total;
    }

    private static int genPermsInner(int idx, int usedMask, int[] a, int[][] perms, int off) {
        if (idx == a.length) perms[off++] = a.clone();
        else for (int i = 0; i < a.length; i++) {
            int m = 1 << (a[idx] = i);
            if ((usedMask & m) == 0) off = genPermsInner(idx+1, usedMask | m, a, perms, off);
        }
        return off;
    }

    static class Job implements Runnable {
        private volatile long subtotal = 0;
        private final int n;
        private final int[][] perms;
        private final int shift;
        private final Map<CanonicalMatrix, Integer> unseen;

        public Job(int n, int[][] perms, int shift, Map<CanonicalMatrix, Integer> unseen) {
            this.n = n;
            this.perms = perms;
            this.shift = shift;
            this.unseen = unseen;
        }

        public void run() {
            long result = 0;
            int[][] perms = this.perms;
            Map<CanonicalMatrix, Integer> unseen = this.unseen;
            while (!unseen.isEmpty()) {
                int m = unseen.values().iterator().next();
                Set<CanonicalMatrix> equiv = new HashSet<CanonicalMatrix>();
                for (int[] perm : perms) {
                    CanonicalMatrix canonical = new CanonicalMatrix(m, perm);
                    if (equiv.add(canonical)) {
                        result += canonical.weight() << shift;
                        unseen.remove(canonical);
                    }
                }
            }

            subtotal = result;
        }
    }

    static class CanonicalMatrix {
        private final int[] a;
        private final int hash;

        public CanonicalMatrix(int m, int[] r) {
            this(permuteRows(m, r));
        }

        public CanonicalMatrix(int[] a) {
            this.a = a;
            Arrays.sort(a);

            int h = 0;
            for (int i : a) h = h * 37 + i;
            hash = h;
        }

        private static int[] permuteRows(int m, int[] perm) {
            int[] cols = new int[perm.length];
            for (int i = 0; i < perm.length; i++) {
                for (int j = 0; j < cols.length; j++) cols[j] |= ((m >> (perm[i] + j)) & 1L) << i;
            }
            return cols;
        }

        public int sum() {
            int sum = 0;
            for (int i : a) sum += i;
            return sum;
        }

        public int weight() {
            int prev = -1, count = 0, weight = FACT[a.length];
            for (int col : a) {
                if (col == prev) weight /= ++count;
                else {
                    prev = col;
                    count = 1;
                }
            }
            return weight;
        }

        @Override public boolean equals(Object obj) {
            // Deliberately unsuitable for general-purpose use, but helps catch bugs faster.
            CanonicalMatrix that = (CanonicalMatrix)obj;
            for (int i = 0; i < a.length; i++) {
                if (a[i] != that.a[i]) return false;
            }
            return true;
        }

        @Override public int hashCode() {
            return hash;
        }
    }
}

के रूप में सहेजें HankelCombinatorics.java, संकलित करें , के रूप javac HankelCombinatorics.javaमें चलाएँ java -Xmx2G HankelCombinatorics

साथ NUM_THREADS = 4मेरी क्वाड-कोर मशीन पर यह हो जाता है 20420819767436के लिए n=8में 50 से 55 सेकंड गुजर चुके, रन के बीच परिवर्तनशीलता का एक उचित राशि के साथ; मुझे उम्मीद है कि इसे आसानी से आपकी ऑक्टा-कोर मशीन पर ही प्रबंधित किया जाना चाहिए, लेकिन इसे प्राप्त करने में एक घंटे या उससे अधिक समय लगेगा n=9

यह काम किस प्रकार करता है

यह देखते हुए n, 2^(2n-1)बाइनरी nएक्स nहैंकेल मैट्रीस हैं। पंक्तियों को n!तरीकों से, और स्तंभों को n!तरीकों से अनुमति दी जा सकती है। बस हमें दोहरी गिनती से बचने की जरूरत है ...

यदि आप प्रत्येक पंक्ति के योग की गणना करते हैं, तो न तो पंक्तियों की अनुमति देना और न ही स्तंभों की अनुमति देने से रकमों का गुणन बदल जाता है। उदाहरण के लिए

0 1 1 0 1
1 1 0 1 0
1 0 1 0 0
0 1 0 0 1
1 0 0 1 0

पंक्ति राशि मल्टीसेट है {3, 3, 2, 2, 2}, और इसलिए इससे प्राप्त सभी हैन्केलेबल मैट्रीस हैं। इसका मतलब है कि हम इन पंक्ति योग मल्टीसेट्स द्वारा हैंकेल मैट्रिस को समूह बना सकते हैं और फिर प्रत्येक प्रोसेसर को स्वतंत्र रूप से संभाल सकते हैं, जिससे कई प्रोसेसर एईएस का शोषण होता है।

एक शोषक समरूपता भी है: जितने शून्य से अधिक वाले शून्य होते हैं, उससे अधिक शून्य वाले मैट्रिक्स के साथ पूर्वाग्रह होते हैं।

दोहरी-गणना तब होता है जब हेंकल मैट्रिक्स M_1पंक्ति क्रमचय के साथ r_1और स्तंभ क्रमचय c_1हेंकल मैट्रिक्स से मेल खाता है M_2पंक्ति क्रमचय के साथ r_2और स्तंभ क्रमचय c_2(दो अप करने के लिए साथ नहीं बल्कि तीनों M_1 = M_2, r_1 = r_2, c_1 = c_2)। पंक्ति और स्तंभ क्रमपरिवर्तन स्वतंत्र हैं, इसलिए यदि हम पंक्ति क्रमचय लागू r_1करने के लिए M_1और पंक्ति क्रमचय r_2करने के लिए M_2, कॉलम multisets के रूप में बराबर होना चाहिए। इसलिए प्रत्येक समूह के लिए, मैं समूह में एक मैट्रिक्स के लिए एक पंक्ति क्रमांकन लागू करके प्राप्त किए गए सभी कॉलम मल्टीसेट्स की गणना करता हूं। मल्टीसेट का एक कैनोनिकल प्रतिनिधित्व प्राप्त करने का आसान तरीका कॉलम को सॉर्ट करना है, और यह अगले चरण में भी उपयोगी है।

विशिष्ट कॉलम मल्टीसेट प्राप्त करने के बाद, हमें यह पता लगाने की आवश्यकता है कि n!प्रत्येक के कितने क्रमांकन अद्वितीय हैं। इस बिंदु पर, डबल-काउंटिंग केवल तभी हो सकती है जब किसी दिए गए कॉलम मल्टीसेट में डुप्लिकेट कॉलम हैं: हमें जो करने की आवश्यकता है वह मल्टीसेट में प्रत्येक अलग कॉलम की घटनाओं की संख्या को गिनने के लिए है और फिर संबंधित बहुराष्ट्रीय गुणांक की गणना करें। चूंकि कॉलम छांटे गए हैं, इसलिए गिनती करना आसान है।

अंत में हम उन्हें जोड़ते हैं।

असममित जटिलता पूर्ण सटीकता की गणना करने के लिए तुच्छ नहीं है, क्योंकि हमें सेट के बारे में कुछ धारणाएं बनाने की आवश्यकता है। हम 2^(2n-2) n!कॉलम मल्टीसेट के आदेश पर मूल्यांकन करते हैं , n^2 ln nप्रत्येक के लिए समय (छंटाई सहित); यदि समूहन एक ln nकारक से अधिक नहीं लेता है, तो हमारे पास समय की जटिलता है Theta(4^n n! n^2 ln n)। लेकिन चूंकि घातीय कारक पूरी तरह से बहुपदों पर हावी हैं, इसलिए यह Theta(4^n n!) = Theta((4n/e)^n)


यह बहुत प्रभावशाली है। क्या आप उस एल्गोरिथ्म के बारे में कुछ कह सकते हैं जिसका आपने उपयोग किया है?

3

को Python2 / 3

एक धीमी भाषा में सुंदर अनुभवहीन व्यक्ति:

import itertools

def permute_rows(m):
    for perm in itertools.permutations(m):
        yield perm

def permute_columns(m):
    T = zip(*m)
    for perm in itertools.permutations(T):
        yield zip(*perm)

N = 1
while True:
    base_template = ["abcdefghijklmnopqrstuvwxyz"[i:i+N] for i in range(N)]

    templates = set()
    for c in permute_rows(base_template):
        for m in permute_columns(c):
            templates.add("".join("".join(row) for row in m))

    def possibs(free, templates):
        if free == 2*N - 1:
            return set(int(t, 2) for t in templates)

        s = set()
        for b in "01":
            new_templates = set(t.replace("abcdefghijklmnopqrstuvwxyz"[free], b) for t in templates)
            s |= possibs(free + 1, new_templates)

        return s

    print(len(possibs(0, templates)))
    N += 1

लिखकर चलाएं python script.py


आपके पास पायथन 2/3 के रूप में सूचीबद्ध भाषा है, लेकिन इसके लिए पायथन 2 में काम करने के लिए, आपको from __future__ import print_function(या कुछ और) की आवश्यकता नहीं है ?
एलेक्स ए।

2
@AlexA। आम तौर पर, हाँ, लेकिन इस मामले में नहीं। जब आप टाइप करते हैं तो पायथन 2 के व्यवहार पर विचार करें return(1)। अब :) के returnसाथ बदलेंprint
orlp

ठंडा! मुझे हर दिन कुछ नया सीखना अच्छा लगता है। :)
एलेक्स ए।

2

हास्केल

import Data.List
import Data.Hashable
import Control.Parallel.Strategies
import Control.Parallel
import qualified Data.HashSet as S

main = mapM putStrLn $ map (show.countHankellable) [1..]

a§b=[a!!i|i<-b]

hashNub :: (Hashable a, Eq a) => [a] -> [a]
hashNub l = go S.empty l
    where
      go _ []     = []
      go s (x:xs) = if x `S.member` s then go s xs
                                    else x : go (S.insert x s) xs

pmap = parMap rseq

makeMatrix :: Int->[Bool]->[[Bool]]
makeMatrix n vars = [vars§[i..i+n-1]|i<-[0..n-1]]

countHankellable :: Int -> Int
countHankellable n = let
    s = permutations [0..n-1]
    conjugates m = concat[permutations[r§q|r<-m]|q<-s]
    variableSets = sequence [[True,False]|x<-[0..2*(n-1)]]
 in
    length.hashNub.concat.pmap (conjugates.makeMatrix n ) $ variableSets

पीटर के रूप में तेजी से पास कहीं नहीं है - वह एक बहुत प्रभावशाली सेटअप है जो वह वहां मिला है! अब इंटरनेट से बहुत अधिक कोड कॉपी किए गए हैं। उपयोग:

$ ghc -threaded hankell.hs
$ ./hankell

एक हास्केल जवाब हमेशा स्वागत है। धन्यवाद।

@ लेम्बिक - आपकी मशीन पर मेरा क्या काम है?
अलेक्जेंडर-ब्रेट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.