संपत्ति X के बिना उच्चतम स्कोरिंग मैट्रिक्स का पता लगाएं


14

यह चुनौती आंशिक रूप से एक एल्गोरिदम चुनौती है, आंशिक रूप से एक अनुकूलन चुनौती है और आंशिक रूप से बस एक सबसे तेज़ कोड चुनौती है।

एक चक्रीय मैट्रिक्स पूरी तरह से अपनी पहली पंक्ति द्वारा निर्दिष्ट है r। शेष पंक्तियाँ rपंक्ति अनुक्रमणिका के बराबर ऑफसेट के साथ पंक्ति के प्रत्येक चक्रीय क्रमपरिवर्तन हैं । हम चक्रीय मैट्रेस की अनुमति देंगे जो कि वर्ग नहीं हैं ताकि वे बस अपनी आखिरी पंक्तियों को याद कर रहे हों। हालांकि हम हमेशा यह मानते हैं कि पंक्तियों की संख्या स्तंभों की संख्या से अधिक नहीं है। उदाहरण के लिए, 5 चक्रीय मैट्रिक्स द्वारा निम्नलिखित 3 पर विचार करें।

10111
11011
11101

हम कहते हैं कि मैट्रिक्स में गुणनफल X होता है यदि उसमें गैर-समान सूचकांकों वाले स्तंभों के दो गैर-खाली सेट होते हैं जिनमें समान (वेक्टर) योग होता है। दो स्तंभों का सदिश योग केवल दो स्तंभों का एक तत्व-वार योग है। यह दो स्तंभों का योग है जिसमें xप्रत्येक तत्व एक और स्तंभ है जिसमें xतत्व शामिल हैं।

तुच्छ रूप से ऊपर वाले मैट्रिक्स में गुणनफल X है क्योंकि पहले और अंतिम कॉलम समान हैं। पहचान मैट्रिक्स में कभी संपत्ति X नहीं होती है।

यदि हम ऊपर दिए गए मैट्रिक्स के अंतिम कॉलम को हटाते हैं तो हमें एक उदाहरण मिलता है जिसमें संपत्ति X नहीं है और यह 4/3 का स्कोर देगा।

1011
1101
1110

काम

कार्य उच्चतम स्कोरिंग चक्रीय मैट्रिक्स को खोजने के लिए कोड लिखना है, जिनकी प्रविष्टियां सभी 0 या 1 हैं और जिसमें संपत्ति X नहीं है।

स्कोर

आपका स्कोर आपके सर्वश्रेष्ठ स्कोरिंग मैट्रिक्स में पंक्तियों की संख्या से विभाजित संख्या कॉलम होगा।

टाई ब्रेकर

यदि दो उत्तरों में समान स्कोर है, तो पहले ने पहली जीत दर्ज की।

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

संकेत

12/8 का स्कोर प्राप्त करना बहुत कठिन नहीं है।

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

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

अग्रणी प्रविष्टियाँ

  • पीटर टेलर (जावा) द्वारा 36/19
  • सबॉप्टिमस प्राइम द्वारा 32/17 (C #)
  • जस्टफॉल द्वारा 21/12 (पायथन 2)

आह, गुण X स्तंभों पर है, न कि पंक्तियों पर।
ऑप्टिमाइज़र

जैसा कि लिखा गया है, 1 बाय 2 मैट्रिक्स 01 में संपत्ति एक्स है क्योंकि पहले कॉलम के सेट में खाली सेट के समान वेक्टर राशि है। शायद आपके लिए कॉलम के गैर-रिक्त सेट का मतलब था? मुझे लगता है कि यह क्लीनर है, हालांकि इसे बदलना नहीं है।
xnor

2
नियमों का सबसे आसान पठन अभी भी है 01जिसमें संपत्ति X है (1) = (0) + (1):। यदि आप उसे बाहर करना चाहते हैं, तो आपको यह कहना चाहिए कि स्तंभों के दो सेटों का तिरस्कार होना चाहिए।
पीटर टेलर

1
यह प्रश्न इस समस्या पर अधिक जानकारी देगा (संपत्ति X की जाँच करना कितना कठिन है, जो कि NP-hard है, दुर्भाग्य से) mathoverflow.net/questions/157634/…
8

3
वर्तमान में हम 2^mसंपत्ति को जांचने के लिए सभी कॉलम संयोजनों को केवल बलपूर्वक मजबूर कर रहे हैं। यदि हम किसी तरह "मध्य में मिलने" योजना को तैयार कर सकते हैं (" m * 2^(m/2)
सब्मिट

जवाबों:


11

16/9 20/11 22/12 28/15 30/16 32/17 34/18 36/19 (जावा)

यह खोज स्थान और लागत को कम करने के लिए कई विचारों का उपयोग करता है। कोड के पुराने संस्करणों पर अधिक विवरण के लिए संशोधन इतिहास देखें।

  • यह स्पष्ट है कि वॉग हम केवल सर्कुलर मेट्रिसेस पर विचार कर सकते हैं जिसमें पहली पंक्ति एक लिंडन शब्द है : यदि यह शब्द गैर-अभाज्य है तो इसमें संपत्ति X होना चाहिए, और अन्यथा हम स्कोर या संपत्ति X को प्रभावित किए बिना घुमा सकते हैं।
  • मनाया कम विजेताओं से heuristics आधार पर, मैं अब 50% घनत्व के साथ लोगों पर शुरू (के यानी एक ही नंबर लिंडन शब्द के माध्यम से पुनरावृत्ति कर रहा हूँ 0और 1) और बाहर काम कर; मैं निश्चित घनत्व वाले हार और लिंडन शब्दों के लिए ए ग्रे कोड में वर्णित एल्गोरिदम का उपयोग लगातार परिशोधित समय , सवादा और विलियम्स, सैद्धांतिक कंप्यूटर विज्ञान 502 (2013): 46-54 में करता हूं।
  • एक अनुभवजन्य अवलोकन यह है कि मूल्य जोड़े में होते हैं: प्रत्येक इष्टतम लिंडन शब्द जो मैंने पाया है कि स्कोर इसके उलट के समान है। इसलिए मुझे इस तरह के प्रत्येक जोड़े के आधे हिस्से पर विचार करके दो स्पीडअप का एक कारक मिलता है।
  • मेरे मूल कोड ने BigIntegerसटीक परीक्षण दिया। मुझे एक महत्वपूर्ण गति में सुधार, झूठी नकारात्मक के जोखिम पर, एक बड़े प्राइमरी मोडुलो को संचालित करने और प्राथमिकताओं में सब कुछ रखकर। मैंने जो प्रधान चुना है, वह 2 57 से छोटा सबसे बड़ा है , क्योंकि यह बिना किसी अतिप्रवाह के मेरे नोटरी वेक्टर प्रतिनिधित्व के आधार से गुणा करने की अनुमति देता है।
  • मैंने सबॉप्टिमस प्राइम के विधर्मी को चुरा लिया है कि आकार के बढ़ते क्रम में सबसेट पर विचार करके त्वरित अस्वीकृति प्राप्त करना संभव है। मैंने अब उस विचार को टर्नरी सबसेट मीट-इन-द-मिडिल अप्रोच के साथ टकराने वाले सबसेट के लिए परीक्षण करने के लिए मिला दिया है। (करने के लिए क्रेडिट KennyTM पूर्णांक सबसेट समस्या से दृष्टिकोण अनुकूल करने के लिए कोशिश कर सुझाव देने के लिए, मुझे लगता है कि XNOR और मैं जिस तरह से यह काफी एक साथ करने के लिए देखा था)। दो सबसेट की तलाश करने के बजाय, जिसमें प्रत्येक कॉलम 0 या 1 बार शामिल हो सकता है और एक ही राशि हो, हम एक सबसेट की तलाश करते हैं, जिसमें प्रत्येक कॉलम -1, 0, या 1 बार और शून्य के योग हो सकते हैं। यह स्मृति आवश्यकताओं को काफी कम कर देता है।
  • स्मृति आवश्यकताओं में दो बचत का एक अतिरिक्त कारक है, यह देखते हुए कि चूंकि प्रत्येक तत्व में {-1,0,1}^mइसकी नकारात्मकता है, {-1,0,1}^mइसलिए यह केवल दो में से एक को संग्रहीत करने के लिए आवश्यक है।
  • मैं कस्टम हैशमप कार्यान्वयन का उपयोग करके स्मृति आवश्यकताओं और प्रदर्शन में सुधार करता हूं। 36/19 का परीक्षण करने के लिए 3 ^ 18 sums की आवश्यकता होती है, और 3 ^ 18 लॉन्ग लगभग 3GB बिना किसी ओवरहेड के होते हैं - मैंने इसे 6GB ढेर दिया क्योंकि 4GB पर्याप्त नहीं था; 8GB RAM के भीतर किसी भी आगे (यानी परीक्षण 38/20) जाने के लिए लॉन्ग के बजाय इन्ट को स्टोर करने के लिए और अनुकूलन की आवश्यकता होगी। 20 बिट्स के साथ यह कहना आवश्यक है कि कौन सा सब्मिट उस राशि का उत्पादन करता है जो 12 बिट्स को छोड़ देगी और बाल्टी से निहित बिट्स; मुझे डर है कि किसी भी हिट को पाने के लिए बहुत सारे झूठे टकराव होंगे।
  • चूंकि सबूतों के वजन से पता चलता है कि हमें देखना चाहिए 2n/(n+1), इसलिए मैं सिर्फ परीक्षण करके चीजों को तेज कर रहा हूं।
  • सांख्यिकीय आउटपुट को आश्वस्त करने वाले कुछ अनावश्यक लेकिन फिर से है।
import java.util.*;

// Aiming to find a solution for (2n, n+1).
public class PPCG41021_QRTernary_FixedDensity {
    private static final int N = 36;
    private static int density;
    private static long start;
    private static long nextProgressReport;

    public static void main(String[] args) {
        start = System.nanoTime();
        nextProgressReport = start + 5 * 60 * 1000000000L;

        // 0, -1, 1, -2, 2, ...
        for (int i = 0; i < N - 1; i++) {
            int off = i >> 1;
            if ((i & 1) == 1) off = ~off;
            density = (N >> 1) + off;

            // Iterate over Lyndon words of length N and given density.
            for (int j = 0; j < N; j++) a[j] = j < N - density ? '0' : '1';
            c = 1;
            Bs[1] = N - density;
            Bt[1] = density;
            gen(N - density, density, 1);
            System.out.println("----");
        }

        System.out.println("Finished in " + (System.nanoTime() - start)/1000000 + " ms");
    }

    private static int c;
    private static int[] Bs = new int[N + 1], Bt = new int[N + 1];
    private static char[] a = new char[N];
    private static void gen(int s, int t, int r) {
        if (s > 0 && t > 0) {
            int j = oracle(s, t, r);
            for (int i = t - 1; i >= j; i--) {
                updateBlock(s, t, i);
                char tmp = a[s - 1]; a[s - 1] = a[s+t-i - 1]; a[s+t-i - 1] = tmp;
                gen(s-1, t-i, testSuffix(r) ? c-1 : r);
                tmp = a[s - 1]; a[s - 1] = a[s+t-i - 1]; a[s+t-i - 1] = tmp;
                restoreBlock(s, t, i);
            }
        }
        visit();
    }

    private static int oracle(int s, int t, int r) {
        int j = pseudoOracle(s, t, r);
        updateBlock(s, t, j);
        int p = testNecklace(testSuffix(r) ? c - 1 : r);
        restoreBlock(s, t, j);
        return p == N ? j : j + 1;
    }

    private static int pseudoOracle(int s, int t, int r) {
        if (s == 1) return t;
        if (c == 1) return s == 2 ? N / 2 : 1;
        if (s - 1 > Bs[r] + 1) return 0;
        if (s - 1 == Bs[r] + 1) return cmpPair(s-1, t, Bs[c-1]+1, Bt[c-1]) <= 0 ? 0 : 1;
        if (s - 1 == Bs[r]) {
            if (s == 2) return Math.max(t - Bt[r], (t+1) >> 1);
            return Math.max(t - Bt[r], (cmpPair(s-1, t, Bs[c-1] + 1, Bt[c-1]) <= 0) ? 0 : 1); 
        }
        if (s == Bs[r]) return t;
        throw new UnsupportedOperationException("Hit the case not covered by the paper or its accompanying code");
    }

    private static int testNecklace(int r) {
        if (density == 0 || density == N) return 1;
        int p = 0;
        for (int i = 0; i < c; i++) {
            if (r - i <= 0) r += c;
            if (cmpBlocks(c-i, r-i) < 0) return 0;
            if (cmpBlocks(c-i, r-1) > 0) return N;
            if (r < c) p += Bs[r-i] + Bt[r-i];
        }
        return p;
    }

    private static int cmpPair(int a1, int a2, int b1, int b2) {
        if (a1 < b1) return -1;
        if (a1 > b1) return 1;
        if (a2 < b2) return -1;
        if (a2 > b2) return 1;
        return 0;
    }

    private static int cmpBlocks(int i, int j) {
        return cmpPair(Bs[i], Bt[i], Bs[j], Bt[j]);
    }

    private static boolean testSuffix(int r) {
        for (int i = 0; i < r; i++) {
            if (c - 1 - i == r) return true;
            if (cmpBlocks(c-1-i, r-i) < 0) return false;
            if (cmpBlocks(c-1-i, r-1) > 0) return true;
        }
        return false;
    }

    private static void updateBlock(int s, int t, int i) {
        if (i == 0 && c > 1) {
            Bs[c-1]++;
            Bs[c] = s - 1;
        }
        else {
            Bs[c] = 1;
            Bt[c] = i;
            Bs[c+1] = s-1;
            Bt[c+1] = t-i;
            c++;
        }
    }

    private static void restoreBlock(int s, int t, int i) {
        if (i == 0 && (c > 0 || (Bs[1] != 1 || Bt[1] != 0))) {
            Bs[c-1]--;
            Bs[c] = s;
        }
        else {
            Bs[c-1] = s;
            Bt[c-1] = t;
            c--;
        }
    }

    private static long[] stats = new long[N/2+1];
    private static long visited = 0;
    private static void visit() {
        String word = new String(a);

        visited++;
        if (precedesReversal(word) && testTernary(word)) System.out.println(word + " after " + (System.nanoTime() - start)/1000000 + " ms");
        if (System.nanoTime() > nextProgressReport) {
            System.out.println("Progress: visited " + visited + "; stats " + Arrays.toString(stats) + " after " + (System.nanoTime() - start)/1000000 + " ms");
             nextProgressReport += 5 * 60 * 1000000000L;
        }
    }

    private static boolean precedesReversal(String w) {
        int n = w.length();
        StringBuilder rev = new StringBuilder(w);
        rev.reverse();
        rev.append(rev, 0, n);
        for (int i = 0; i < n; i++) {
            if (rev.substring(i, i + n).compareTo(w) < 0) return false;
        }
        return true;
    }

    private static boolean testTernary(String word) {
        int n = word.length();
        String rep = word + word;

        int base = 1;
        for (char ch : word.toCharArray()) base += ch & 1;

        // Operating base b for b up to 32 implies that we can multiply by b modulo p<2^57 without overflowing a long.
        // We're storing 3^(n/2) ~= 2^(0.8*n) sums, so while n < 35.6 we don't get *too* bad a probability of false reject.
        // (In fact the birthday paradox assumes independence, and our values aren't independent, so we're better off than that).
        long p = (1L << 57) - 13;
        long[] basis = new long[n];
        basis[0] = 1;
        for (int i = 1; i < basis.length; i++) basis[i] = (basis[i-1] * base) % p;

        int rows = n / 2 + 1;
        long[] colVals = new long[n];
        for (int col = 0; col < n; col++) {
            for (int row = 0; row < rows; row++) {
                colVals[col] = (colVals[col] + basis[row] * (rep.charAt(row + col) & 1)) % p;
            }
        }

        MapInt57Int27 map = new MapInt57Int27();
        // Special-case the initial insertion.
        int[] oldLens = new int[map.entries.length];
        int[] oldSupercounts = new int[1 << 10];
        {
            // count = 1
            for (int k = 0; k < n/2; k++) {
                int val = 1 << (25 - k);
                if (!map.put(colVals[k], val)) { stats[1]++; return false; }
                if (!map.put(colVals[k + n/2], val + (1 << 26))) { stats[1]++; return false; }
            }
        }
        final long keyMask = (1L << 37) - 1;
        for (int count = 2; count <= n/2; count++) {
            int[] lens = map.counts.clone();
            int[] supercounts = map.supercounts.clone();
            for (int sup = 0; sup < 1 << 10; sup++) {
                int unaccountedFor = supercounts[sup] - oldSupercounts[sup];
                for (int supi = 0; supi < 1 << 10 && unaccountedFor > 0; supi++) {
                    int i = (sup << 10) + supi;
                    int stop = lens[i];
                    unaccountedFor -= stop - oldLens[i];
                    for (int j = oldLens[i]; j < stop; j++) {
                        long existingKV = map.entries[i][j];
                        long existingKey = ((existingKV & keyMask) << 20) + i;
                        int existingVal = (int)(existingKV >>> 37);

                        // For each possible prepend...
                        int half = (existingVal >> 26) * n/2;
                        // We have 27 bits of key, of which the top marks the half, so 26 bits. That means there are 6 bits at the top which we need to not count.
                        int k = Integer.numberOfLeadingZeros(existingVal << 6) - 1;
                        while (k >= 0) {
                            int newVal = existingVal | (1 << (25 - k));
                            long pos = (existingKey + colVals[k + half]) % p;
                            if (pos << 1 > p) pos = p - pos;
                            if (pos == 0 || !map.put(pos, newVal)) { stats[count]++; return false; }
                            long neg = (p - existingKey + colVals[k + half]) % p;
                            if (neg << 1 > p) neg = p - neg;
                            if (neg == 0 || !map.put(neg, newVal)) { stats[count]++; return false; }
                            k--;
                        }
                    }
                }
            }
            oldLens = lens;
            oldSupercounts = supercounts;
        }

        stats[n/2]++;
        return true;
    }

    static class MapInt57Int27 {
        private long[][] entries;
        private int[] counts;
        private int[] supercounts;

        public MapInt57Int27() {
            entries = new long[1 << 20][];
            counts = new int[1 << 20];
            supercounts = new int[1 << 10];
        }

        public boolean put(long key, int val) {
            int bucket = (int)(key & (entries.length - 1));
            long insert = (key >>> 20) | (((long)val) << 37);
            final long mask = (1L << 37) - 1;

            long[] chain = entries[bucket];
            if (chain == null) {
                chain = new long[16];
                entries[bucket] = chain;
                chain[0] = insert;
                counts[bucket]++;
                supercounts[bucket >> 10]++;
                return true;
            }

            int stop = counts[bucket];
            for (int i = 0; i < stop; i++) {
                if ((chain[i] & mask) == (insert & mask)) {
                    return false;
                }
            }

            if (stop == chain.length) {
                long[] newChain = new long[chain.length < 512 ? chain.length << 1 : chain.length + 512];
                System.arraycopy(chain, 0, newChain, 0, chain.length);
                entries[bucket] = newChain;
                chain = newChain;
            }
            chain[stop] = insert;
            counts[bucket]++;
            supercounts[bucket >> 10]++;
            return true;
        }
    }
}

जो पहला पाया जाता है

000001001010110001000101001111111111

और वह 15 घंटे में ही हिट हो गया।

छोटे विजेता:

4/3:    0111                       (plus 8 different 8/6)
9/6:    001001011                  (and 5 others)
11/7:   00010100111                (and 3 others)
13/8:   0001001101011              (and 5 others)
15/9:   000010110110111            (and 21 others)
16/9:   0000101110111011           (and 1 other)
20/11:  00000101111011110111       (and others)
22/12:  0000001100110011101011     (and others)
24/13:  000000101011101011101011   (and others)
26/14:  00000001101110010011010111 (and others)
28/15:  0000000010000111100111010111 (and others)
30/16:  000000001011001110011010101111 (and probably others)
32/17:  00001100010010100100101011111111 (and others)
34/18:  0000101000100101000110010111111111 (and others)

यह एक अच्छा सुधार है। ऐसा लगता है कि लिंडन शब्दों का उपयोग करने का मतलब है कि आपको केवल 2 ^ n के बजाय पहली पंक्ति के लिए लगभग 2 ^ n / n बाइनरी स्ट्रिंग्स की जांच करने की आवश्यकता है।

जैसा कि आप BigInteger के प्रत्येक अंक को एक मैट्रिक्स सेल के रूप में उपयोग कर रहे हैं, क्या n> 10 होने पर गलत उत्तर नहीं होगा?
kennytm

@KennyTM, ध्यान दें कि दूसरा पैरामीटर मूलांक है। एक छोटा सा बग है: मुझे इसके nबजाय उपयोग करना चाहिए rows, हालांकि यह इस मायने में असफल है कि यह अवैध समाधान स्वीकार करने के बजाय वैध समाधान छोड़ देगा। यह परिणामों को भी प्रभावित नहीं करता है।
पीटर टेलर

1
मुझे लगता है कि हम व्यावहारिक रूप से इस स्कोर तक सीमित हैं, क्योंकि प्रॉपर्टी एक्स की जाँच में बहुत समय लगता है, जब तक कि हमें एक और समतुल्य स्थिति नहीं मिली जिसका मूल्यांकन तेजी से किया जा सके। इसलिए मैं यह देखने के लिए बहुत उत्सुक था कि "गैर-प्राइम" का तात्पर्य है संपत्ति एक्स = डी
जस्टफॉल

1
@SuboptimusPrime, मैंने इसे लोगों पर पाया। pm.sfu.ca/~kya17/teaching/math343/16-343.pdf और बग को ठीक किया। दिलचस्प बात यह है कि अब मैं लिंडन शब्दों के माध्यम से इसका उपयोग करने वाला एल्गोरिथ्म संबंधित एल्गोरिदम का एक वर्ग है, जो के-एन-एन सबसेट भी करता है, इसलिए मैं कुछ कोड को रिफैक्ट करने और साझा करने में सक्षम हो सकता हूं।
पीटर टेलर

9

अजगर 2 - 21/12

यह साबित करने की प्रक्रिया में कि किसी के लिए 2-(3/n)हमेशा मौजूद हैn

इस सवाल से प्रेरित होकर , मैंने संभावित ब्रेटरों को बल देने के लिए डी ब्रूजन अनुक्रम का उपयोग किया । और के लिए bruteforcing के बाद n=6,7,8,9,10, मैं एक पैटर्न है कि उच्चतम समाधान हमेशा के आकार में है पाया (n, 2n-3)

इसलिए मैंने मैट्रिक्स के उस आकार को ठीक करने के लिए एक और तरीका बनाया, और चीजों को गति देने के लिए मल्टीप्रोसेसिंग का उपयोग किया, क्योंकि यह कार्य बहुत अधिक वितरण योग्य है। 16-कोर ubuntu में, यह n=12लगभग 4 मिनट के लिए समाधान पा सकता है :

कोशिश करना (0, 254)
कोशिश कर (254, 509)
कोशिश करना (509, 764)
कोशिश कर रहा है (764, 1018)
कोशिश कर रहा है (1018, 1273)
कोशिश कर (1273, 1528)
कोशिश कर (1528, 1782)
कोशिश कर रहा है (1782, 2037)
कोशिश कर रहा है (2037, 2292)
कोशिश कर (2292, 2546)
कोशिश कर रहा है (2546, 2801)
कोशिश कर (2801, 3056)
कोशिश कर (3056, 3310)
कोशिश कर रहा है (3820, 4075)
कोशिश कर (3565, 3820)
कोशिश कर (3310, 3565)
(1625, 1646)
[[० ० ० १ ० १ १ १ १ १ १ ० ० ० १] ०]
 [0 0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0]
 [0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0]
 [1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0]
 [० ० १ १ १ १ १ १ १ ० ० १ ० १ १ ० ० ० १]
 [0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1]
 [1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0]
 [0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1]
 [१ १ १ १ १ ० ० १ १ ० १ १ ० ० ० १ ० ०]
 [1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 1]
 [१ १ ० ० ० १ ० ० १ १ ० ० १ ० १] १]
 [1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 1 1 1]
(12, 21)
स्कोर: 1.7500

असली 4m9.121s
उपयोगकर्ता 42m47.472s
sys 0m5.780s

अभिकलन का बड़ा हिस्सा संपत्ति X की जाँच करने के लिए जाता है, जिसे सभी सबसेट (सबसेट होते हैं 2^(2n-3)) की जाँच करने की आवश्यकता होती है

ध्यान दें कि मैं पहली पंक्ति को बाईं ओर घुमाता हूं, प्रश्न में दाईं ओर नहीं। लेकिन ये बराबर हैं क्योंकि आप पूरे मैट्रिक्स को उल्टा कर सकते हैं। =)

कोड:

import math
import numpy as np
from itertools import combinations
from multiprocessing import Process, Queue, cpu_count

def de_bruijn(k, n):
    """
    De Bruijn sequence for alphabet k
    and subsequences of length n.
    """
    alphabet = list(range(k))
    a = [0] * k * n
    sequence = []
    def db(t, p):
        if t > n:
            if n % p == 0:
                for j in range(1, p + 1):
                    sequence.append(a[j])
        else:
            a[t] = a[t - p]
            db(t + 1, p)
            for j in range(a[t - p] + 1, k):
                a[t] = j
                db(t + 1, t)
    db(1, 1)
    return sequence

def generate_cyclic_matrix(seq, n):
    result = []
    for i in range(n):
        result.append(seq[i:]+seq[:i])
    return np.array(result)

def generate_cyclic_matrix_without_property_x(n=3, n_jobs=-1):
    seq = de_bruijn(2,n)
    seq = seq + seq[:n/2]
    max_idx = len(seq)
    max_score = 1
    max_matrix = np.array([[]])
    max_ij = (0,0)
    workers = []
    queue = Queue()
    if n_jobs < 0:
        n_jobs += cpu_count()+1
    for i in range(n_jobs):
        worker = Process(target=worker_function, args=(seq,i*(2**n-2*n+3)/n_jobs, (i+1)*(2**n-2*n+3)/n_jobs, n, queue))
        workers.append(worker)
        worker.start()
    (result, max_ij) = queue.get()
    for worker in workers:
        worker.terminate()
    return (result, max_ij)

def worker_function(seq,min_idx,max_idx,n,queue):
    print 'Trying (%d, %d)' % (min_idx, max_idx)
    for i in range(min_idx, max_idx):
        j = i+2*n-3
        result = generate_cyclic_matrix(seq[i:j], n)
        if has_property_x(result):
            continue
        else:
            queue.put( (result, (i,j)) )
            return

def has_property_x(mat):
    vecs = zip(*mat)
    vector_sums = set()
    for i in range(1, len(vecs)+1):
        for combination in combinations(vecs, i):
            vector_sum = tuple(sum(combination, np.array([0]*len(mat))))
            if vector_sum in vector_sums:
                return True
            else:
                vector_sums.add(vector_sum)
    return False

def main():
    import sys
    n = int(sys.argv[1])
    if len(sys.argv) > 2:
        n_jobs = int(sys.argv[2])
    else:
        n_jobs = -1
    (matrix, ij) = generate_cyclic_matrix_without_property_x(n, n_jobs)
    print ij
    print matrix
    print matrix.shape
    print 'Score: %.4f' % (float(matrix.shape[1])/matrix.shape[0])

if __name__ == '__main__':
    main()

पुराना उत्तर, संदर्भ के लिए

अब तक का इष्टतम समाधान ( n=10):

(855, 872)
[[१ १ ० १ १ ० १ ० १ १ १ १ १ ० १ १ ०]
 [१ ० १ १ ० १ ० १ १ १ १ ० १ १ १ ० १]
 [० १ ० १ १ ० १ १ १ १ १ १ १ १ १ ० १]
 [1 0 1 0 0 1 1 1 1 0 1 1 1 0 0 1 1 0]
 [० १ ० ० १ १ १ १ १ १ १ १ १ ० १ १ ० १]
 [१ ० ० १ १ १ १ १ ० १ १ १ ० १ १ ० १ ०]
 [० ० १ १ १ १ १ ० १ १ १ ० १ १ ० १ १]
 [० १ १ १ १ १ ० १ १ १ ० १ १ ० १ ० १]
 [१ १ १ १ १ ० १ १ १ ० १ १ ० १ १ ० ०]
 [१ १ १ ० १ १ १ १ ० १ १ ० १ १ ० ० १]]
(१०, १,)
स्कोर: 1.7000

के लिए n=7:

(86, 97)
[[० १ १ १ १ ० १ ० ० १ १]
 [1 1 1 0 1 0 0 1 1 1 0]
 [1 1 0 1 0 0 1 1 1 0 1]
 [1 0 1 0 0 1 1 1 0 0 1]
 [० १ ० ० १ १ १ ० १ १ १]
 [१ ० ० १ १ १ १ ० १ १ १ ०]
 [० ० १ १ १ १ ० १ १ १ ० १]]
(,, ११)
स्कोर: 1.5714

ओपी द्वारा वर्णित आकार के साथ एक समाधान n=8:

(२२ (, २३ ९)
[[० १ १ १ १ १ १ १ १ ० १ १ ०]
 [1 0 1 1 1 1 1 0 0 1 1 0 0]
 [0 1 1 1 1 1 1 0 1 1 0 0 1]
 [1 1 1 1 1 0 0 1 1 0 0 1 0]
 [1 1 1 1 0 1 1 0 0 1 0 1]
 [1 1 1 0 1 1 0 0 1 0 1 1]
 [1 1 0 1 1 0 0 1 0 1 1 1]
 [1 0 1 1 0 0 1 0 1 1 1 1]]
(,, १२)
स्कोर: 1.5000

लेकिन एक बेहतर ( n=8):

(95, 108)
[[० १ १ ० ० १ ० ० १ १ ० १]
 [1 1 0 0 1 0 0 0 1 1 0 1 0]
 [1 0 0 1 0 0 0 1 1 0 0 0 1]
 [० ० १ ० ० ० १ १ ० १ १]
 [0 1 0 0 0 1 1 0 0 1 1 1 0]
 [1 0 0 0 1 1 0 0 1 1 1 0 0]
 [० ० १ १ १ ० १ १ ० १ १ ० १]
 [० ० १ १ ० १ १ ० १ १ ० १ ०]]
(,, १३)
स्कोर: 1.6250

इसमें एक और इष्टतम समाधान भी पाया गया n=9:

(103, 118)
[[० १ १ १ १ १ १ ० ० ० १ १ ० १]
 [1 0 1 1 1 0 0 0 0 1 1 0 0 1 0]
 [0 1 1 1 0 0 0 0 1 1 0 0 1 0 1]
 [1 1 1 0 0 0 0 1 1 0 0 1 0 0 0]
 [1 1 0 0 0 0 1 1 0 0 1 0 1 0 1]
 [1 0 0 0 0 1 1 0 0 1 0 1 0 1 1]
 [० ० ० १ १ १ ० ० १ १ ० १ १ १]
 [० ० ० १ १ ० ० १ १ ० १ १ १ ०]
 [० ० १ १ ० १ १ ० १ १ १ १ १ ०]]
(९, १५)
स्कोर: 1.6667

कोड इस प्रकार है। यह केवल क्रूर बल है, लेकिन कम से कम यह ओपी के दावे से बेहतर कुछ पा सकता है =)

import numpy as np
from itertools import combinations

def de_bruijn(k, n):
    """
    De Bruijn sequence for alphabet k
    and subsequences of length n.
    """
    alphabet = list(range(k))
    a = [0] * k * n
    sequence = []
    def db(t, p):
        if t > n:
            if n % p == 0:
                for j in range(1, p + 1):
                    sequence.append(a[j])
        else:
            a[t] = a[t - p]
            db(t + 1, p)
            for j in range(a[t - p] + 1, k):
                a[t] = j
                db(t + 1, t)
    db(1, 1)
    return sequence

def generate_cyclic_matrix(seq, n):
    result = []
    for i in range(n):
        result.append(seq[i:]+seq[:i])
    return np.array(result)

def generate_cyclic_matrix_without_property_x(n=3):
    seq = de_bruijn(2,n)
    max_score = 0
    max_matrix = []
    max_ij = (0,0)
    for i in range(2**n+1):
        for j in range(i+n, 2**n+1):
            score = float(j-i)/n
            if score <= max_score:
                continue
            result = generate_cyclic_matrix(seq[i:j], n)
            if has_property_x(result):
                continue
            else:
                if score > max_score:
                    max_score = score
                    max_matrix = result
                    max_ij = (i,j)
    return (max_matrix, max_ij)

def has_property_x(mat):
    vecs = zip(*mat)
    vector_sums = set()
    for i in range(1, len(vecs)):
        for combination in combinations(vecs, i):
            vector_sum = tuple(sum(combination, np.array([0]*len(mat))))
            if vector_sum in vector_sums:
                return True
            else:
                vector_sums.add(vector_sum)
    return False

def main():
    import sys
    n = int(sys.argv[1])
    (matrix, ij) = generate_cyclic_matrix_without_property_x(n)
    print ij
    print matrix
    print matrix.shape
    print 'Score: %.4f' % (float(matrix.shape[1])/matrix.shape[0])

if __name__ == '__main__':
    main()

एक महान शुरुआत :)

2
@ लिम्बिक अब मैं लगभग किसी भी स्कोर (सीमित समय तक सीमित) को हरा सकता हूँ 2. नीचे किसी भी स्कोर का दावा करने वाला कोई भी व्यक्ति = =)
१२:५२

उस स्थिति में, क्या आप 19/10 को हरा सकते हैं?

@ लेम्बिक मुझे नहीं लगता कि मैं कर सकता हूं। यह आवश्यक है n >= 31, जिसका अर्थ है कि मुझे 2^(2n-3) = 2^5931-आयामी वेक्टर के संयोजन की जांच करने की आवश्यकता होगी । हमारे जीवनकाल में समाप्त नहीं होगा = D
जस्टफुल

2
आप को साबित कर सकते हैं कि आप हमेशा के एक मैट्रिक्स प्राप्त कर सकते हैंn*(2n-3)
XNOR

7

24/13 26/14 28/15 30/16 32/17 (C #)

संपादित करें: मेरे उत्तर से पुरानी जानकारी हटा दी गई। मैं पीटर टेलर के रूप में ज्यादातर एक ही एल्गोरिथ्म का उपयोग कर रहा हूं ( संपादित करें: ऐसा लगता है कि वह अब एक बेहतर एल्गोरिथ्म का उपयोग कर रहा है), हालांकि मैंने अपनी आशावादी आशाओं में से कुछ जोड़ा है:

  • मैंने उसी वेक्टर राशि के साथ कॉलम सेटों की खोज करने के लिए "मध्य में मिलने" की रणनीति को लागू किया है ( यह केनीटीएम की टिप्पणी द्वारा सुझाया गया है )। इस रणनीति ने मेमोरी उपयोग में बहुत सुधार किया, लेकिन यह बहुत धीमा है, इसलिए मैंने HasPropertyXFastफ़ंक्शन को जोड़ा है , जो "बीच में मिलने" का उपयोग करने से पहले समान योगों के साथ छोटे सेट होने पर जल्दी से चेक करता है।
  • HasPropertyXFast फ़ंक्शन में कॉलम सेट के माध्यम से पुनरावृत्ति करते समय , मैं 1 कॉलम के साथ कॉलम सेट की जांच करना शुरू करता हूं, फिर 2, 3 और इसी तरह। जैसे ही कॉलम रकम की पहली टक्कर मिलती है, फ़ंक्शन वापस आ जाता है। व्यवहार में इसका मतलब है कि मुझे आमतौर पर लाखों के बजाय कुछ सैकड़ों या हजारों कॉलम सेट की जांच करनी होगी।
  • मैं longसंपूर्ण स्तंभों और उनके वेक्टर रकमों को संग्रहीत और तुलना करने के लिए चर का उपयोग कर रहा हूं । यह दृष्टिकोण कम से कम परिमाण का एक क्रम है, जिसमें स्तंभों की तुलना सरणियों से की जा सकती है।
  • मैंने हैशसेट का अपना कार्यान्वयन जोड़ा है, long डेटा प्रकार और मेरे उपयोग पैटर्न के लिए अनुकूलित किया है ।
  • मैं स्मृति आबंटनों की संख्या को कम करने और प्रदर्शन में सुधार करने के लिए आवेदन के पूरे जीवनकाल के लिए एक ही 3 हैशटैग का पुनः उपयोग कर रहा हूं।
  • बहुपरत समर्थन।

कार्यक्रम का उत्पादन:

00000000000111011101010010011111
10000000000011101110101001001111
11000000000001110111010100100111
11100000000000111011101010010011
11110000000000011101110101001001
11111000000000001110111010100100
01111100000000000111011101010010
00111110000000000011101110101001
10011111000000000001110111010100
01001111100000000000111011101010
00100111110000000000011101110101
10010011111000000000001110111010
01001001111100000000000111011101
10100100111110000000000011101110
01010010011111000000000001110111
10101001001111100000000000111011
11010100100111110000000000011101
Score: 32/17 = 1,88235294117647
Time elapsed: 02:11:05.9791250

कोड:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

class Program
{
    const int MaxWidth = 32;
    const int MaxHeight = 17;

    static object _lyndonWordLock = new object();

    static void Main(string[] args)
    {
        Stopwatch sw = Stopwatch.StartNew();
        double maxScore = 0;
        const int minHeight = 17; // 1
        for (int height = minHeight; height <= MaxHeight; height++)
        {
            Console.WriteLine("Row count = " + height);
            Console.WriteLine("Time elapsed: " + sw.Elapsed + "\r\n");

            int minWidth = Math.Max(height, (int)(height * maxScore) + 1);
            for (int width = minWidth; width <= MaxWidth; width++)
            {
#if MULTITHREADING
                int[,] matrix = FindMatrixParallel(width, height);
#else
                int[,] matrix = FindMatrix(width, height);
#endif
                if (matrix != null)
                {
                    PrintMatrix(matrix);
                    Console.WriteLine("Time elapsed: " + sw.Elapsed + "\r\n");
                    maxScore = (double)width / height;
                }
                else
                    break;
            }
        }
    }

#if MULTITHREADING
    static int[,] FindMatrixParallel(int width, int height)
    {
        _lyndonWord = 0;
        _stopSearch = false;

        int threadCount = Environment.ProcessorCount;
        Task<int[,]>[] tasks = new Task<int[,]>[threadCount];
        for (int i = 0; i < threadCount; i++)
            tasks[i] = Task<int[,]>.Run(() => FindMatrix(width, height));

        int index = Task.WaitAny(tasks);
        if (tasks[index].Result != null)
            _stopSearch = true;

        Task.WaitAll(tasks);
        foreach (Task<int[,]> task in tasks)
            if (task.Result != null)
                return task.Result;

        return null;
    }

    static volatile bool _stopSearch;
#endif

    static int[,] FindMatrix(int width, int height)
    {
#if MULTITHREADING
        _columnSums = new LongSet();
        _left = new LongSet();
        _right = new LongSet();
#endif

        foreach (long rowTemplate in GetLyndonWords(width))
        {
            int[,] matrix = new int[width, height];
            for (int x = 0; x < width; x++)
            {
                int cellValue = (int)(rowTemplate >> (width - 1 - x)) % 2;
                for (int y = 0; y < height; y++)
                    matrix[(x + y) % width, y] = cellValue;
            }

            if (!HasPropertyX(matrix))
                return matrix;

#if MULTITHREADING
            if (_stopSearch)
                return null;
#endif
        }

        return null;
    }

#if MULTITHREADING
    static long _lyndonWord;
#endif

    static IEnumerable<long> GetLyndonWords(int length)
    {
        long lyndonWord = 0;
        long max = (1L << (length - 1)) - 1;
        while (lyndonWord <= max)
        {
            if ((lyndonWord % 2 != 0) && PrecedesReversal(lyndonWord, length))
                yield return lyndonWord;

#if MULTITHREADING
            lock (_lyndonWordLock)
            {
                if (_lyndonWord <= max)
                    _lyndonWord = NextLyndonWord(_lyndonWord, length);
                else
                    yield break;

                lyndonWord = _lyndonWord;
            }
#else
            lyndonWord = NextLyndonWord(lyndonWord, length);
#endif
        }
    }

    static readonly int[] _lookup =
    {
        32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
        0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
    };

    static int NumberOfTrailingZeros(uint i)
    {
        return _lookup[(i & -i) % 37];
    }

    static long NextLyndonWord(long w, int length)
    {
        if (w == 0)
            return 1;

        int currentLength = length - NumberOfTrailingZeros((uint)w);
        while (currentLength < length)
        {
            w += w >> currentLength;
            currentLength *= 2;
        }

        w++;

        return w;
    }

    private static bool PrecedesReversal(long lyndonWord, int length)
    {
        int shift = length - 1;

        long reverse = 0;
        for (int i = 0; i < length; i++)
        {
            long bit = (lyndonWord >> i) % 2;
            reverse |= bit << (shift - i);
        }

        for (int i = 0; i < length; i++)
        {
            if (reverse < lyndonWord)
                return false;

            long bit = reverse % 2;
            reverse /= 2;
            reverse += bit << shift;
        }

        return true;
    }

#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _left = new LongSet();
#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _right = new LongSet();

    static bool HasPropertyX(int[,] matrix)
    {
        long[] matrixColumns = GetMatrixColumns(matrix);
        if (matrixColumns.Length == 1)
            return false;

        return HasPropertyXFast(matrixColumns) || MeetInTheMiddle(matrixColumns);
    }

    static bool MeetInTheMiddle(long[] matrixColumns)
    {
        long[] leftColumns = matrixColumns.Take(matrixColumns.Length / 2).ToArray();
        long[] rightColumns = matrixColumns.Skip(matrixColumns.Length / 2).ToArray();

        if (PrepareHashSet(leftColumns, _left) || PrepareHashSet(rightColumns, _right))
            return true;

        foreach (long columnSum in _left.GetValues())
            if (_right.Contains(columnSum))
                return true;

        return false;
    }

    static bool PrepareHashSet(long[] columns, LongSet sums)
    {
        int setSize = (int)System.Numerics.BigInteger.Pow(3, columns.Length);
        sums.Reset(setSize, setSize);
        foreach (long column in columns)
        {
            foreach (long sum in sums.GetValues())
                if (!sums.Add(sum + column) || !sums.Add(sum - column))
                    return true;

            if (!sums.Add(column) || !sums.Add(-column))
                return true;
        }

        return false;
    }

#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _columnSums = new LongSet();

    static bool HasPropertyXFast(long[] matrixColumns)
    {
        int width = matrixColumns.Length;

        int maxColumnCount = width / 3;
        _columnSums.Reset(width, SumOfBinomialCoefficients(width, maxColumnCount));

        int resetBit, setBit;
        for (int k = 1; k <= maxColumnCount; k++)
        {
            uint columnMask = (1u << k) - 1;
            long sum = 0;
            for (int i = 0; i < k; i++)
                sum += matrixColumns[i];

            while (true)
            {
                if (!_columnSums.Add(sum))
                    return true;
                if (!NextColumnMask(columnMask, k, width, out resetBit, out setBit))
                    break;
                columnMask ^= (1u << resetBit) ^ (1u << setBit);
                sum = sum - matrixColumns[resetBit] + matrixColumns[setBit];
            }
        }

        return false;
    }

    // stolen from Peter Taylor
    static bool NextColumnMask(uint mask, int k, int n, out int resetBit, out int setBit)
    {
        int gap = NumberOfTrailingZeros(~mask);
        int next = 1 + NumberOfTrailingZeros(mask & (mask + 1));

        if (((k - gap) & 1) == 0)
        {
            if (gap == 0)
            {
                resetBit = next - 1;
                setBit = next - 2;
            }
            else if (gap == 1)
            {
                resetBit = 0;
                setBit = 1;
            }
            else
            {
                resetBit = gap - 2;
                setBit = gap;
            }
        }
        else
        {
            if (next == n)
            {
                resetBit = 0;
                setBit = 0;
                return false;
            }

            if ((mask & (1 << next)) == 0)
            {
                if (gap == 0)
                {
                    resetBit = next - 1;
                    setBit = next;
                }
                else
                {
                    resetBit = gap - 1;
                    setBit = next;
                }
            }
            else
            {
                resetBit = next;
                setBit = gap;
            }
        }

        return true;
    }

    static long[] GetMatrixColumns(int[,] matrix)
    {
        int width = matrix.GetLength(0);
        int height = matrix.GetLength(1);

        long[] result = new long[width];
        for (int x = 0; x < width; x++)
        {
            long column = 0;
            for (int y = 0; y < height; y++)
            {
                column *= 13;
                if (matrix[x, y] == 1)
                    column++;
            }

            result[x] = column;
        }

        return result;
    }

    static int SumOfBinomialCoefficients(int n, int k)
    {
        int result = 0;
        for (int i = 0; i <= k; i++)
            result += BinomialCoefficient(n, i);
        return result;
    }

    static int BinomialCoefficient(int n, int k)
    {
        long result = 1;
        for (int i = n - k + 1; i <= n; i++)
            result *= i;
        for (int i = 2; i <= k; i++)
            result /= i;
        return (int)result;
    }

    static void PrintMatrix(int[,] matrix)
    {
        int width = matrix.GetLength(0);
        int height = matrix.GetLength(1);

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
                Console.Write(matrix[x, y]);
            Console.WriteLine();
        }

        Console.WriteLine("Score: {0}/{1} = {2}", width, height, (double)width / height);
    }
}


class LongSet
{
    private static readonly int[] primes =
    {
        17, 37, 67, 89, 113, 149, 191, 239, 307, 389, 487, 613, 769, 967, 1213, 1523, 1907,
        2389, 2999, 3761, 4703, 5879, 7349, 9187, 11489, 14369, 17971, 22469, 28087, 35111,
        43889, 54869, 68597, 85751, 107197, 133999, 167521, 209431, 261791, 327247, 409063,
        511333, 639167, 798961, 998717, 1248407, 1560511, 1950643, 2438309, 3047909,
        809891, 4762367, 5952959, 7441219, 9301529, 11626913, 14533661, 18167089, 22708867,
        28386089, 35482627, 44353297, 55441637, 69302071, 86627603, 108284507, 135355669,
        169194593, 211493263, 264366593, 330458263, 413072843, 516341057, 645426329,
        806782913, 1008478649, 1260598321
    };

    private int[] _buckets;
    private int[] _nextItemIndexes;
    private long[] _items;
    private int _count;
    private int _minCapacity;
    private int _maxCapacity;
    private int _currentCapacity;

    public LongSet()
    {
        Initialize(0, 0);
    }

    private int GetPrime(int capacity)
    {
        foreach (int prime in primes)
            if (prime >= capacity)
                return prime;

        return int.MaxValue;
    }

    public void Reset(int minCapacity, int maxCapacity)
    {
        if (maxCapacity > _maxCapacity)
            Initialize(minCapacity, maxCapacity);
        else
            ClearBuckets();
    }

    private void Initialize(int minCapacity, int maxCapacity)
    {
        _minCapacity = GetPrime(minCapacity);
        _maxCapacity = GetPrime(maxCapacity);
        _currentCapacity = _minCapacity;

        _buckets = new int[_maxCapacity];
        _nextItemIndexes = new int[_maxCapacity];
        _items = new long[_maxCapacity];
        _count = 0;
    }

    private void ClearBuckets()
    {
        Array.Clear(_buckets, 0, _currentCapacity);
        _count = 0;
        _currentCapacity = _minCapacity;
    }

    public bool Add(long value)
    {
        int bucket = (int)((ulong)value % (ulong)_currentCapacity);
        for (int i = _buckets[bucket] - 1; i >= 0; i = _nextItemIndexes[i])
            if (_items[i] == value)
                return false;

        if (_count == _currentCapacity)
        {
            Grow();
            bucket = (int)((ulong)value % (ulong)_currentCapacity);
        }

        int index = _count;
        _items[index] = value;
        _nextItemIndexes[index] = _buckets[bucket] - 1;
        _buckets[bucket] = index + 1;
        _count++;

        return true;
    }

    private void Grow()
    {
        Array.Clear(_buckets, 0, _currentCapacity);

        const int growthFactor = 8;
        int newCapacity = GetPrime(_currentCapacity * growthFactor);
        if (newCapacity > _maxCapacity)
            newCapacity = _maxCapacity;
        _currentCapacity = newCapacity;

        for (int i = 0; i < _count; i++)
        {
            int bucket = (int)((ulong)_items[i] % (ulong)newCapacity);
            _nextItemIndexes[i] = _buckets[bucket] - 1;
            _buckets[bucket] = i + 1;
        }
    }

    public bool Contains(long value)
    {
        int bucket = (int)((ulong)value % (ulong)_buckets.Length);
        for (int i = _buckets[bucket] - 1; i >= 0; i = _nextItemIndexes[i])
            if (_items[i] == value)
                return true;

        return false;
    }

    public IReadOnlyList<long> GetValues()
    {
        return new ArraySegment<long>(_items, 0, _count);
    }
}

विन्यास फाइल:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

कुछ संबंध में आप अनुकूलित के बजाय निराशावादी लगते हैं। केवल एक चीज जो वास्तव में एक अनुकूलन की तरह दिखती है, बिट्स का उपयोग करके क्लैश की अनुमति देता है ulongऔर उपयोग करने के बजाय शिफ्ट रैप को अनुमति देता है BigInteger
पीटर टेलर

@PeterTaylor सबसे महत्वपूर्ण अनुकूलन HasPropertyX फ़ंक्शन में है। जैसे ही कॉलम sums की पहली टक्कर मिलती है, फ़ंक्शन वापस आ जाता है (आपके स्कोर लिंडनॉर्ड फ़ंक्शन के विपरीत)। मैंने कॉलम मास्क को इस तरह से सॉर्ट किया है कि हम सबसे पहले कॉलम सेट की जांच करते हैं जो टकराने की अधिक संभावना है। इन दोनों आशाओं ने परिमाण के क्रम से प्रदर्शन में सुधार किया।
सबोप्टिमस प्राइम

यद्यपि प्रदर्शन परिवर्तन अक्सर आश्चर्यजनक होते हैं, सिद्धांत रूप में प्रारंभिक गर्भपात 2 के एक कारक से अधिक नहीं देना चाहिए, और GetSumOfColumnsएक अतिरिक्त लूप जोड़ता है जो मुझे उस कारक से अधिक खर्च करने की उम्मीद करेगा। मास्क सॉर्टिंग दिलचस्प लगता है: शायद आप कर सकते हैं इसके बारे में थोड़ा बात करने के लिए उत्तर को संपादित करें? (और कुछ बिंदु पर मैं शुरुआती गर्भपात करने के लिए एक वैकल्पिक तरीके के साथ प्रयोग करूंगा: इसका कारण यह है कि मैं यह नहीं कर सकता कि हैशसेट समवर्ती यात्रा और संशोधन का समर्थन नहीं करता है, लेकिन मेरे पास एक पुनरावृत्ति की आवश्यकता से बचने के लिए विचार हैं) ।
पीटर टेलर

2
@ अन्याय, एक निश्चित आकार के सबसेट पर चलने के लिए ग्रे-एस्क दृष्टिकोण का उपयोग करना वास्तव में सार्थक है। इसने मुझे 9 मिनट से कम समय में 9/14 का पता लगाने और उनमें से 34 को दो घंटे में खोजने की अनुमति दी, जिस बिंदु पर मैंने गर्भपात किया था। वर्तमान में यह देखने के लिए परीक्षण किया जा रहा है कि मुझे उचित समय में 28/15 मिल सकता है या नहीं।
पीटर टेलर

1
@ लेम्बिक, मैंने .५.५ घंटे में २15/१५ का विस्तार किया। 31/16 के रूप में लंबे समय के बारे में 3 बार ले जाएगा - एक सप्ताह से अधिक। हम दोनों ने कुछ अनुकूलन किए हैं जब से मैंने 29/15 का परीक्षण शुरू किया है, इसलिए शायद अब यह एक सप्ताह तक हो जाएगा। मेरे कोड या SuboptimusPrime के कोड को संकलित करने और यदि आपके पास एक कंप्यूटर है जिसे आप उस लंबे समय तक छोड़ सकते हैं, तो उसे चलाने से आपको रोकने के लिए कुछ भी नहीं है।
पीटर टेलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.