हामिंग दूरी क्रमों की संख्या गिनें


9

आलोचनात्मक अंतर समान अवधि की दो तार के बीच पदों, जिस पर इसी प्रतीकों अलग हैं की संख्या है।

आज्ञा देना Pबाइनरी स्ट्रिंग की लंबाई nऔर Tबाइनरी स्ट्रिंग की लंबाई हो 2n-1। हम बायीं और दायीं ओर के क्रम में हर- लेयरिंग सबस्ट्रिंग के nबीच हैमिंग की दूरी की गणना कर सकते हैं और उन्हें एक सरणी (या सूची) में डाल सकते हैं।PnT

उदाहरण हैमिंग दूरी अनुक्रम

चलो P = 101और T = 01100। इस जोड़ी से आपको मिलने वाली हैमिंग दूरियों का क्रम है 2,2,1

कार्य

बढ़ाने के लिए nपर शुरू n=1, द्विआधारी तार के सभी संभव जोड़े पर विचार Pलंबाई की nऔर Tलंबाई की 2n-1। इस 2**(n+2n-1)तरह की जोड़ियाँ हैं और इसलिए हैमिंग के कई सीक्वेंस हैं। हालांकि उन दृश्यों में से कई समान होंगे। कार्य यह पता लगाना है कि प्रत्येक के लिए कितने विशिष्ट हैं n

आपका कोड प्रति मूल्य एक नंबर आउटपुट होना चाहिए n

स्कोर

आपका स्कोर उच्चतम है जो nआपका कोड 5 मिनट में मेरी मशीन पर पहुंचता है। समय कुल चल रहे समय के लिए है, न कि केवल उसके लिए समय n

किसी जीत

उच्चतम स्कोर वाला व्यक्ति जीतता है। यदि दो या अधिक लोग एक ही स्कोर के साथ समाप्त होते हैं तो यह पहला उत्तर है जो जीतता है।

उदाहरण उत्तर

के लिए nसे 1करने के लिए 8इष्टतम उत्तर दिए गए हैं 2, 9, 48, 297, 2040, 15425, 125232, 1070553

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

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

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

उत्तर देना

  • 11 ++ में सी + फेर्सम द्वारा। 25 सेकंड।
  • एंड्रयू एपस्टीन द्वारा सी ++ में 11 । 176 सेकंड।
  • नील द्वारा 10 जावास्क्रिप्ट में । 54 सेकंड।
  • 9 नेमी द्वारा हास्केल में । 4 मिनट और 59 सेकंड।
  • 8 में जावास्क्रिप्ट fənɛtɪk द्वारा। दस पल।

.. कोई भी उपलब्ध मुफ्त * भाषाएं?
स्टेवि ग्रिफिन

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


4
@SIGSEGV fastest-codeदोनों कोड स्तर अनुकूलन और एक अच्छा एल्गोरिथ्म के माध्यम से अनुकूलन के लिए अधिक स्थान छोड़ देता है। इसलिए मुझे लगता है कि इससे faster-codeबेहतर है faster-algorithm
दादा

जवाबों:


3

C ++ 11 (11 या 12 के लिए मिलना चाहिए)

फिलहाल यह सिंगल-थ्रेडेड है।

संकलन करना:

g++ -std=c++11 -O2 -march=native feersum.cpp
#include <iostream>
#include <unordered_set>
#include <vector>
#include <unordered_map>
#include <string.h>

using seq = uint64_t;
using bitvec = uint32_t;
using seqset = std::unordered_set<seq>;
using std::vector;

#define popcount __builtin_popcount
#define MAX_N_BITS 4

bitvec leading(bitvec v, int n) {
    return v & ((1U << n) - 1);
}
bitvec trailing(bitvec v, int n, int total) {
    return v >> (total - n);
}

bitvec maxP(int n) {
    return 1 << (n - 1);  // ~P, ~T symmetry
}

void prefixes(int n, int pre, int P, seqset& p) {
    p.clear();
    for (bitvec pref = 0; pref < (1U << pre); pref++) {
        seq s = 0;
        for (int i = 0; i < pre; i++) {
            seq ham = popcount(trailing(pref, pre - i, pre) ^ leading(P, pre - i));
            s |= ham << i * MAX_N_BITS;
        }
        p.insert(s);
    }
}



vector<seqset> suffixes(int n, int suf, int off) {
    vector<seqset> S(maxP(n));
    for (bitvec P = 0; P < maxP(n); P++) {
        for (bitvec suff = 0; suff < (1U << suf); suff++) {
            seq s = 0;
            for (int i = 0; i < suf; i++) {
                seq ham = popcount(leading(suff, i + 1) ^ trailing(P, i + 1, n));
                s |= ham << (off + i) * MAX_N_BITS;
            }
            S[P].insert(s);
        }
    }
    return S;
}



template<typename T> 
void mids(int n, int npre, int nsuf, int mid, bitvec P, T& S, const seqset& pre) {
    seq mask = (1ULL << (npre + 1) * MAX_N_BITS) - 1;
    for(bitvec m = 0; m < 1U << mid; m++) {
        int pc = popcount(P ^ m);
        if(pc * 2 > n) continue; // symmetry of T -> ~T : replaces x with n - x
        seq s = (seq)pc << npre * MAX_N_BITS;
        for(int i = 0; i < npre; i++)
            s |= (seq)popcount(trailing(P, n - npre + i, n) ^ leading(m, n - npre + i)) << i * MAX_N_BITS;
        for(int i = 0; i < nsuf; i++)
            s |= (seq)popcount(leading(P, mid - 1 - i) ^ trailing(m, mid - 1 - i, mid)) << (npre + 1 + i) * MAX_N_BITS;
        for(seq a: pre)
            S[(s + a) & mask].insert(P | (s + a) << n);
    }
}

uint64_t f(int n) {
    if (n >= 1 << MAX_N_BITS) {
        std::cerr << "n too big";
        exit(1);
    }
    int tlen = 2*n - 1;
    int mid = n;
    int npre = (tlen - mid) / 2;
    if(n>6) --npre;
    int nsuf = tlen - npre - mid;
    seqset preset;
    auto sufs = suffixes(n, nsuf, npre + 1);
    std::unordered_map<seq, std::unordered_set<uint64_t>> premid;
    for(bitvec P = 0; P < maxP(n); P++) {
        prefixes(n, npre, P, preset);
        mids(n, npre, nsuf, mid, P, premid, preset);
    }
    uint64_t ans = 0;
    using counter = uint8_t;
    vector<counter> found((size_t)1 << nsuf * MAX_N_BITS);
    counter iz = 0;
    for(auto& z: premid) {
        ++iz;
        if(!iz) {
            memset(&found[0], 0, found.size() * sizeof(counter));
            ++iz;
        }
        for(auto& pair: z.second) {
            seq s = pair >> n;
            uint64_t count = 0;
            bitvec P = pair & (maxP(n) - 1);
            for(seq t: sufs[P]) {
                seq suff = (s + t) >> (npre + 1) * MAX_N_BITS;
                if (found[suff] != iz) {
                    ++count;
                    found[suff] = iz;
                }
            }
            int middle = int(s >> npre * MAX_N_BITS) & ~(~0U << MAX_N_BITS);
            ans += count << (middle * 2 != n);
        }
    }

    return ans;
}

int main() {
    for (int i = 1; ; i++)
        std::cout << i << ' ' << f(i) << std::endl;
}

30 सेकंड से भी कम समय में 11 के लिए जाओ!

मामले में यह रुचि है:feersum.cpp:111:61: warning: shifting a negative signed value is undefined [-Wshift-negative-value] int middle = int(s >> npre * MAX_N_BITS) & ~(~0 << MAX_N_BITS);

5

हास्केल, स्कोर 9

import Data.Bits
import Data.List
import qualified Data.IntSet as S

main = mapM_ (print . S.size . S.fromList . hd) [1..9]

hd :: Int -> [Int]
hd n = [foldl' (\s e->s*m+e) 0 [popCount $ xor p (shiftR t i .&. m)|i<-[(0::Int)..n-1]] | let m=2^n-1,p<-[(0::Int)..2^n-1],t<-[(0::Int)..2^(2*n-1)-1]]

के साथ संकलित करें -O3। यह मेरे 6 साल पुराने लैपटॉप हार्डवेयर पर 6min35s चलता है n=9, इसलिए शायद यह संदर्भ हार्डवेयर पर 5min के अंतर्गत है।

> time ./113785
2
9
48
297
2040
15425
125232
1070553
9530752

real  6m35.763s
user  6m27.690s
sys   0m5.025s

1
6 साल का लैपटॉप? अरे, यह कुछ पुरानी तकनीक है!
मैथ्यू रो

@SIGSEGV: हो सकता है कि यह पुराना हो, लेकिन हैमिंग डिस्टेंस सीक्वेंस की संख्या गिनने के अलावा यह अपना काम बखूबी करता है।
नीमी

4

जावास्क्रिप्ट, स्कोर 10

findHamming = m => { 
    if (m < 2) return 2;
    let popcnt = x => x && (x & 1) + popcnt(x >> 1);
    let a = [...Array(1 << m)].map((_,i) => popcnt(i));
    let t = 0;
    let n = (1 << m) - 1;
    for (let c = 0; c <= m; c++) {
        for (let g = 0; g <= c; g++) {
            let s = new Set;
            for (let i = 1 << m; i--; ) {
                for (let j = 1 << (m - 1); j--; ) {
                    if (a[i ^ j + j] != c) continue;
                    for (let k = 1 << m - 1; k--; ) {
                        if (a[i ^ k] != g) continue;
                        let f = j << m | k;
                        let h = 0;
                        for (l = m - 1; --l; ) h = h * (m + 1) + a[i ^ f >> l & n];
                        s.add(h);
                    }
                }
            }
            t += s.size * (g < c ? 2 : 1);
        }
    }
    return t;
};
let d = Date.now(); for (let m = 1; m < 11; m++) console.log(m, findHamming(m), Date.now() - d);

स्पष्टीकरण: गणना n=10करना मुश्किल है क्योंकि दो अरब से अधिक जोड़े हैं और 26 अरब से अधिक संभावित अनुक्रम हैं। चीजों को गति देने के लिए मैंने गणना को 121 डिब्बे में विभाजित किया। क्योंकि सीक्वेंस बिटवाइज़ सप्लीमेंट के तहत अपरिवर्तनीय होते हैं, मैं सामान्यता के नुकसान के बिना मान सकता हूं कि मध्य बिट Tशून्य है। इसका मतलब है कि मैं अनुक्रम के पहले और अंतिम तत्वों को स्वतंत्र रूप से ऊपर n-1और नीचे के n-1बिट्स से निर्धारित कर सकता हूंT। प्रत्येक बिन पहले और अंतिम तत्वों की एक अलग जोड़ी से मेल खाती है; मैं तब ऊपर और नीचे के सभी संभव बिट्स के माध्यम से लूप करता हूं जो प्रत्येक बिन के अनुरूप होते हैं और अनुक्रम के शेष तत्वों की गणना करते हैं, अंत में प्रत्येक बिन के लिए अद्वितीय दृश्यों की गिनती करते हैं। यह तब कुल 121 डिब्बे के बराबर रहता है। मूल रूप से 45 घंटे लगते हैं, अब यह मेरे एएमडी एफएक्स -8120 पर साढ़े तीन मिनट में थोड़ा सा पूरा हो गया है। संपादित करें: 50% स्पीडअप के लिए @ChristianSievers का धन्यवाद। पूर्ण उत्पादन:

1 2 0
2 9 1
3 48 1
4 297 2
5 2040 7
6 15425 45
7 125232 391
8 1070553 1844
9 9530752 15364
10 86526701 153699

आपका कोड वर्तमान में कोई आउटपुट नहीं देता है।
फेलिपा

@felipa यकीन नहीं है कि आप क्या मतलब है। यह एक अनाम फ़ंक्शन है, इसलिए आप इसे कॉल करते हैं (शायद इसे पहले एक चर को निर्दिष्ट करके और फिर चर को बुलाकर जैसे कि यह एक फ़ंक्शन था) और इसे nएक पैरामीटर के रूप में पास करें । (वहां पैरामीटर नाम की खराब पसंद के लिए खेद है।)
नील

प्रश्न कोड के लिए पूछता है कि 5 मिनट में प्राप्त करने के लिए अधिकतम मूल्य के लिए उत्तर को प्रिंट करता है। "आपके कोड को n के मूल्य प्रति एक संख्या का उत्पादन करना चाहिए।"
फेलिपा

यह बहुत अच्छा होगा यदि आपका कोड n = 1 से काम करता है और प्रत्येक चरण में समय को आउटपुट करता है। सवाल से "समय कुल चल रहे समय के लिए है, न कि केवल उस एन के लिए समय।"

1
@ लेम्बिक ने टाइमिंग कोड जोड़ा और बग के लिए भी काम किया n=1(पता नहीं क्यों यह लटका हुआ है)।
नील

4

सी ++, स्कोर 10 11

यह कुछ सरल समानांतरकरण के साथ, सी ++ में @ नील के उत्तर का अनुवाद है। n=90.4 सेकंड में, n=104.5 सेकंड में और n=11मेरे 2015 मैकबुक प्रो पर लगभग 1 मिनट में पूरा होता है। इसके अलावा, @ChristianSievers के लिए धन्यवाद। @ नील के उत्तर पर उनकी टिप्पणियों के कारण, मैंने कुछ अतिरिक्त समरूपताओं पर ध्यान दिया। मूल 121 बाल्टियों (के लिए n=10) से, 66 बाल्टियों के लिए जब उत्क्रमण का हिसाब लगाया जाता है, तो मैंने सिर्फ 21 बाल्टियाँ प्राप्त की हैं।

#include <iostream>
#include <cstdint>
#include <unordered_set>
#include <thread>
#include <future>
#include <vector>

using namespace std;

constexpr uint32_t popcnt( uint32_t v ) {
    uint32_t c = v - ( ( v >> 1 ) & 0x55555555 );
    c = ( ( c >> 2 ) & 0x33333333 ) + ( c & 0x33333333 );
    c = ( ( c >> 4 ) + c ) & 0x0F0F0F0F;
    c = ( ( c >> 8 ) + c ) & 0x00FF00FF;
    c = ( ( c >> 16 ) + c ) & 0x0000FFFF;
    return c;
}

template<uint32_t N>
struct A {
    constexpr A() : arr() {
        for( auto i = 0; i != N; ++i ) {
            arr[i] = popcnt( i );
        }
    }
    uint8_t arr[N];
};

uint32_t n = ( 1 << M ) - 1;
constexpr auto a = A < 1 << M > ();

uint32_t work( uint32_t c, uint32_t g, uint32_t mult ) {
    unordered_set<uint64_t> s;
    // Empirically derived "optimal" value
    s.reserve( static_cast<uint32_t>( pow( 5, M ) ) );

    for( int i = ( 1 << M ) - 1; i >= 0; i-- ) {
        for( uint32_t j = 1 << ( M - 1 ); j--; ) {
            if( a.arr[i ^ j + j] != c ) {
                continue;
            }

            for( uint32_t k = 1 << ( M - 1 ); k--; ) {
                if( a.arr[i ^ k] != g ) {
                    continue;
                }

                uint64_t f = j << M | k;
                uint64_t h = 0;

                for( uint32_t l = M - 1; --l; ) {
                    h = h * ( M + 1 ) + a.arr[i ^ ( f >> l & n )];
                }

                s.insert( h );
            }
        }
    }

    return s.size() * mult;

}

int main() {
    auto t1 = std::chrono::high_resolution_clock::now();

    if( M == 1 ) {
        auto t2 = std::chrono::high_resolution_clock::now();
        auto seconds = chrono::duration_cast<chrono::milliseconds>( t2 - t1 ).count() / 1000.0;
        cout << M << ": " << 2 << ", " << seconds << endl;
        return 0;
    }

    uint64_t t = 0;
    vector<future<uint32_t>> my_vector;

    if( ( M & 1 ) == 0 ) {
        for( uint32_t c = 0; c <= M / 2; ++c ) {
            for( uint32_t g = c; g <= M / 2; ++g ) {
                uint32_t mult = 8;

                if( c == M / 2 && g == M / 2 ) {
                    mult = 1;
                } else if( g == c || g == M / 2 ) {
                    mult = 4;
                }

                my_vector.push_back( async( work, c, g, mult ) );
            }

        }

        for( auto && f : my_vector ) {
            t += f.get();
        }

    } else {
        for( uint32_t c = 0; c <= ( M - 1 ) / 2; ++c ) {
            for( uint32_t g = c; g <= M - c; ++g ) {
                uint32_t mult = 4;

                if( g == c || g + c == M ) {
                    mult = 2;
                }

                my_vector.push_back( async( work, c, g, mult ) );
            }

        }

        for( auto && f : my_vector ) {
            t += f.get();
        }

    }

    auto t2 = std::chrono::high_resolution_clock::now();
    auto seconds = chrono::duration_cast<chrono::milliseconds>( t2 - t1 ).count() / 1000.0;
    cout << M << ": " << t << ", " << seconds << endl;
    return 0;
}

कोड निष्पादित करने के लिए निम्न स्क्रिप्ट का उपयोग करें:

#!/usr/bin/env bash

for i in {1..10}
do
    clang++ -std=c++14 -march=native -mtune=native -Ofast -fno-exceptions -DM=$i hamming3.cpp -o hamming
    ./hamming
done

आउटपुट इस प्रकार था: (प्रारूप है M: result, seconds)

1: 2, 0
2: 9, 0
3: 48, 0
4: 297, 0
5: 2040, 0
6: 15425, 0.001
7: 125232, 0.004
8: 1070553, 0.029
9: 9530752, 0.419
10: 86526701, 4.459
11: 800164636, 58.865

n=12 एक सूत्र पर गणना करने में 42 मिनट लगे, और 7368225813 का परिणाम दिया गया।


आप इसे क्लैब का उपयोग करके ubuntu में कैसे संकलित करेंगे?
फेलिपा

@felipa मुझे लगता है कि जवाब है sudo apt-get install libiomp-dev

यह बहुत अच्छा होगा यदि आपका कोड n = 1 से काम करता है और प्रत्येक चरण में समय को आउटपुट करता है। सवाल से "समय कुल चल रहे समय के लिए है, न कि केवल उस एन के लिए समय।"

इसे फिर से लागू करने के बजाय आप शायद इस्तेमाल कर सकते हैं __builtin_popcount
नील

@ लेम्बिक: मैं आज बाद में बदलाव करूँगा। @ नील: पोपकंट फ़ंक्शन का केवल संकलन समय पर मूल्यांकन किया जाता है, और मुझे पता नहीं है कि __builtin_popcountएक कॉन्स्ट्रेक्स संदर्भ में कैसे उपयोग किया जाए। मैं भोली कार्यान्वयन के साथ जा सकता था और यह रन समय को प्रभावित नहीं करेगा।
एंड्रयू एपस्टीन

2

जावास्क्रिप्ट 2,9,48,297,2040,15425,125232,1070553,9530752

कंसोल में चलाएं:

console.time("test");
h=(w,x,y,z)=>{retVal=0;while(x||y){if(x%2!=y%2)retVal++;x>>=1;y>>=1}return retVal*Math.pow(w+1,z)};
sum=(x,y)=>x+y;
for(input=1;input<10;input++){
  hammings=new Array(Math.pow(input+1,input));
  for(i=1<<(input-1);i<1<<input;i++){
    for(j=0;j<1<<(2*input);j++){
      hamming=0;
      for(k=0;k<input;k++){
        hamming+=(h(input,(j>>k)%(1<<input),i,k));
      }
      hammings[hamming]=1;
    }
  }
  console.log(hammings.reduce(sum));
}
console.timeEnd("test");

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

या एक स्टैक स्निपेट के रूप में:

कोड सरणी को 1s जोड़कर सरणी को बहुत तेज बनाता है

कोड सभी बाधा दूरी अनुक्रमों को ढूंढता है और उन्हें संख्या आधार (इनपुट + 1) के रूप में मानता है, उन्हें एक सरणी में 1 एस लगाने के लिए उपयोग करता है। नतीजतन, यह n 1s के साथ एक सरणी उत्पन्न करता है जहां n अद्वितीय हैमिंग दूरी अनुक्रमों की संख्या है। अंत में, सरणी में सभी मानों को योग करने के लिए array.reduce () का उपयोग करके 1s की संख्या को गिना जाता है।

यह कोड 10 के इनपुट के लिए नहीं चल पाएगा क्योंकि यह मेमोरी लिमिट को हिट करता है

यह कोड O (2 ^ 2n) समय में चलता है क्योंकि यह कितने तत्व उत्पन्न करता है।


1
अप्रत्याशित रूप से, एक 26 * 10 ^ 9 एलिमेंट एरे बनाने की कोशिश नहीं की जाती है
fprnɛtɪk

n = 9नोड का उपयोग करते हुए मेरे लिए 5 मिनट और 30 सेकंड का समय लगता है।

@Lembik n = 8ने मूल रूप से अपने पीसी पर 24 सेकंड का समय लिया, लेकिन मैं कोड को ऑप्टिमाइज़ करने में सक्षम था, इसलिए n = 86 सेकंड का समय लगा। मैंने तब कोशिश की n = 9और 100 सेकंड लगे।
नील

@ नील आपको जवाब प्रस्तुत करना चाहिए!

यह बहुत अच्छा होगा यदि आपका कोड n = 1 से काम करता है और प्रत्येक चरण में समय को आउटपुट करता है। सवाल से "समय कुल चल रहे समय के लिए है, न कि केवल उस एन के लिए समय।"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.