तुम कितनी ऊंचाई तक जाने में सक्षम हो? (एक कोडिंग + एल्गोरिदम चुनौती)


34

अब जब सभी ने अपने (अक्सर आश्चर्यजनक) निम्न स्तर की कोडिंग विशेषज्ञता विकसित कर ली है, तो पायथन वास्तव में कितना धीमा है? (या आपकी भाषा कितनी तेज़ है?) और हाउ स्लो इज पाइथन रियली (पार्ट II)? यह एक चुनौती का समय है जो एक एल्गोरिथ्म में सुधार करने की आपकी क्षमता को भी बढ़ाएगा।

निम्नलिखित कोड 9. स्थिति लंबाई की एक सूची की गणना iसूची में कम से कम समय की संख्या में गिना जाता है iबाद एक कई शून्य के बीच आंतरिक उत्पादों की गणना करते समय पाया गया Fऔर S। ऐसा करने के लिए, यह Fलंबाई की सभी संभावित सूचियों और लंबाई की nसूचियों Sपर आधारित है n+m-1

#!/usr/bin/python
import itertools
import operator

n=8
m=n+1
leadingzerocounts = [0]*m
for S in itertools.product([-1,1], repeat = n+m-1):
    for F in itertools.product([-1,1], repeat = n):
        i = 0
        while (i<m and sum(map(operator.mul, F, S[i:i+n])) == 0):
            leadingzerocounts[i] +=1
            i+=1
print leadingzerocounts

आउटपुट है

[4587520, 1254400, 347648, 95488, 27264, 9536, 4512, 2128, 1064]

यदि आप इस कोड का उपयोग करके n को 10,12,14,16,18,20 तक बढ़ाते हैं तो यह बहुत तेजी से बहुत धीमा हो जाता है।

नियम

  • चुनौती यह है कि यथासंभव बड़े एन के लिए सही आउटपुट दिया जाए। केवल n के मान भी प्रासंगिक हैं।
  • यदि कोई टाई है, तो सबसे बड़ी n के लिए मेरी मशीन पर जीत सबसे तेज कोड में जाती है।
  • मैं 10 मिनट से अधिक समय लेने वाले कोड का परीक्षण नहीं करने का अधिकार सुरक्षित रखता हूं।
  • आप एल्गोरिथ्म को किसी भी तरह से बदल सकते हैं जब तक आप इसे सही आउटपुट देते हैं। वास्तव में आपको जीतने की दिशा में कोई भी अच्छी प्रगति करने के लिए एल्गोरिदम को बदलना होगा
  • प्रश्न सेट होने पर विजेता को एक सप्ताह से सम्मानित किया जाएगा।
  • इनाम तब दिया जाएगा जब वह ऐसा होगा जो विजेता होने के बाद थोड़ा सा दिया जाएगा।

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

स्थिति

  • सी । n = 12 से 49 सेकंड में @ फ़ोरस द्वारा
  • जावा । n = 16 in 3:07 बजे @PeterTaylor द्वारा
  • सी ++ । n = 16 से 2:21 में @ilmale द्वारा
  • Rpython । n = 22 में 3:11 @primo द्वारा
  • जावा । n = 22 6:56 में @PeterTaylor द्वारा
  • निमरोड । n = 24 9:28 सेकंड में @ReimerBehrends द्वारा

विजेता निमरोड में एक प्रविष्टि के साथ रीमर बेहरेंड्स था!

चेक के रूप में, n = 22 के लिए आउटपुट होना चाहिए [12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]


प्रतियोगिता अब समाप्त हो गई है लेकिन ... मैं हर जमा के लिए 200 अंक की पेशकश करूंगा जो 2 अंक (मेरे कंप्यूटर पर 10 मिनट के भीतर) बढ़ जाता है जब तक कि मैं अंकों से बाहर नहीं निकलता। यह ऑफर हमेशा के लिए खुला है


1
"मैं कोड का परीक्षण करने का अधिकार सुरक्षित रखता हूं जो कुछ मिनटों से अधिक समय लेता है।" > आपको अपनी मशीन पर एक सटीक समय निर्दिष्ट करना चाहिए, अन्यथा इस प्रश्न में एक वस्तुनिष्ठ मानदंड की कमी होगी।
pastebin.com 0mr8spkT

14
मुझे ये पसंद हैं "मेरी गति बढ़ाएं" चुनौतियां। यदि आप इन के साथ एक वाणिज्यिक उत्पाद का निर्माण कर रहे हैं, तो आपके पास एक तेज़ उत्पाद का एक नरक है, और आप एक दुष्ट प्रतिभा भी हैं ।
रेनबोल्ट

1
शायद अधिक जानकारीपूर्ण शीर्षक इस ओर ध्यान आकर्षित करेगा?
TheDoctor

8
यदि हम इस प्रकार की चुनौती देते रहते हैं, तो मुझे लगता है कि हमें इसे दिलचस्प रखने के लिए एक अलग समस्या को हल करने का कम से कम प्रयास करना चाहिए (अतिरिक्त विनिर्देशों के साथ एक ही समस्या पर भिन्नता नहीं)।
ग्रूव्सएनएल

2
@Claudiu उनके CPU में 8 भौतिक कोर हैं, लेकिन भ्रूण / डिकोड और FPU इकाइयां कोर के बीच साझा की जाती हैं। इसलिए जब उन क्षेत्रों में से एक पर अड़चन होती है, तो यह क्वाडकोर की तरह व्यवहार करता है। पूर्णांक तर्क का दुरुपयोग करें और बड़े कोड आकारों से बचें और यह 8-कोर की तरह अधिक है।
स्टीफन 20

जवाबों:


20

निमरोड (एन = 22)

import math, locks

const
  N = 20
  M = N + 1
  FSize = (1 shl N)
  FMax = FSize - 1
  SStep = 1 shl (N-1)
  numThreads = 16

type
  ZeroCounter = array[0..M-1, int]
  ComputeThread = TThread[int]

var
  leadingZeros: ZeroCounter
  lock: TLock
  innerProductTable: array[0..FMax, int8]

proc initInnerProductTable =
  for i in 0..FMax:
    innerProductTable[i] = int8(countBits32(int32(i)) - N div 2)

initInnerProductTable()

proc zeroInnerProduct(i: int): bool =
  innerProductTable[i] == 0

proc search2(lz: var ZeroCounter, s, f, i: int) =
  if zeroInnerProduct(s xor f) and i < M:
    lz[i] += 1 shl (M - i - 1)
    search2(lz, (s shr 1) + 0, f, i+1)
    search2(lz, (s shr 1) + SStep, f, i+1)

when defined(gcc):
  const
    unrollDepth = 1
else:
  const
    unrollDepth = 4

template search(lz: var ZeroCounter, s, f, i: int) =
  when i < unrollDepth:
    if zeroInnerProduct(s xor f) and i < M:
      lz[i] += 1 shl (M - i - 1)
      search(lz, (s shr 1) + 0, f, i+1)
      search(lz, (s shr 1) + SStep, f, i+1)
  else:
    search2(lz, s, f, i)

proc worker(base: int) {.thread.} =
  var lz: ZeroCounter
  for f in countup(base, FMax div 2, numThreads):
    for s in 0..FMax:
      search(lz, s, f, 0)
  acquire(lock)
  for i in 0..M-1:
    leadingZeros[i] += lz[i]*2
  release(lock)

proc main =
  var threads: array[numThreads, ComputeThread]
  for i in 0 .. numThreads-1:
    createThread(threads[i], worker, i)
  for i in 0 .. numThreads-1:
    joinThread(threads[i])

initLock(lock)
main()
echo(@leadingZeros)

संकलन

nimrod cc --threads:on -d:release count.nim

(निम्रोद को डाउनलोड किया जा सकता है यहां है ।)

यह n = 20 के लिए आवंटित समय में चलता है (और n = 18 के लिए जब केवल एक ही धागे का उपयोग करते हुए, उत्तरार्द्ध में लगभग 2 मिनट लगते हैं)।

एल्गोरिथ्म एक पुनरावर्ती खोज का उपयोग करता है, जब भी एक गैर-शून्य आंतरिक उत्पाद का सामना किया जाता है, तो खोज पेड़ को काट देता है। हम किसी भी जोड़ीदार वैक्टर के लिए यह देख कर खोज स्थान को आधे में काट देते हैं(F, -F) हमें केवल एक पर विचार करने की आवश्यकता है क्योंकि दूसरा आंतरिक उत्पादों के सटीक सेटों ( Sभी नकार कर ) का उत्पादन करता है ।

कार्यान्वयन निम्रोद की मेटाप्रोग्रामिंग सुविधाओं का उपयोग पुनरावर्ती खोज के पहले कुछ स्तरों को अनियंत्रित / इनलाइन करने के लिए करता है। यह थोड़ा समय बचाता है जब gcc 4.8 और 4.9 निम्रोड के बैकेंड के रूप में और क्लैंग के लिए उचित राशि का उपयोग करता है।

खोज स्थान को यह देखते हुए आगे बढ़ाया जा सकता है कि हमें केवल एस के मूल्यों पर विचार करने की आवश्यकता है जो एफ की हमारी पसंद से पहले एन पदों की एक समान संख्या में भिन्न है। हालांकि, उस की जटिलता या स्मृति की जरूरत बड़े मूल्यों के लिए पैमाने पर नहीं है। N का, यह देखते हुए कि उन मामलों में लूप बॉडी पूरी तरह से छोड़ दी जाती है।

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

ऐसा लगता है कि समस्या को गतिशील प्रोग्रामिंग के लिए उत्तरदायी होना चाहिए, यह देखते हुए कि पुनरावर्ती खोज कैसे काम करती है, लेकिन उचित मात्रा में स्मृति के साथ ऐसा करने का कोई स्पष्ट तरीका नहीं है।

उदाहरण आउटपुट:

एन = 16:

@[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600]

एन = 18:

@[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]

एन = 20:

@[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]

अन्य कार्यान्वयन के साथ एल्गोरिथ्म की तुलना करने के प्रयोजनों के लिए, N = 16 को एक मशीन का उपयोग करते समय मेरी मशीन पर लगभग 7.9 सेकंड और चार सेकंड का उपयोग करते समय 2.3 सेकंड लगते हैं।

N = 22 को 64-कोर मशीन पर gcc 4.4.6 के साथ लगभग 15 मिनट लगते हैं क्योंकि Nimrod का बैकएंड और 64-बिट पूर्णांक को ओवरलैप करता है leadingZeros[0](संभवतः अहस्ताक्षरित लोगों ने इसे नहीं देखा है)।


अपडेट: मुझे कुछ सुधारों के लिए जगह मिली है। सबसे पहले, दिए गए मूल्य के लिए F, हम संबंधित Sवैक्टर की पहली 16 प्रविष्टियों को ठीक से गणना कर सकते हैं , क्योंकि वे बिल्कुल N/2स्थानों में भिन्न होना चाहिए । इसलिए हम आकार की बिट वैक्टर की एक सूची precompute Nहै कि N/2बिट्स सेट और के प्रारंभिक भाग प्राप्त करने के लिए इन का उपयोग Sसे F

दूसरा, हम यह देख कर पुनरावर्ती खोज में सुधार कर सकते हैं कि हम हमेशा मूल्य जानते हैं F[N](जैसा कि एमएसबी बिट प्रतिनिधित्व में शून्य है)। यह हमें ठीक से भविष्यवाणी करने की अनुमति देता है कि हम किस शाखा में आंतरिक उत्पाद से पुनरावृत्ति करते हैं। जबकि यह वास्तव में हमें पूरी खोज को पुनरावर्ती लूप में बदलने की अनुमति देगा, जो वास्तव में शाखा भविष्यवाणी को थोड़ा पेंच करने के लिए होता है, इसलिए हम शीर्ष स्तरों को इसके मूल रूप में रखते हैं। हम अभी भी कुछ समय बचाते हैं, मुख्य रूप से हम कर रहे शाखाओं की मात्रा को कम करके।

कुछ सफाई के लिए, कोड अब अहस्ताक्षरित पूर्णांक का उपयोग कर रहा है और उन्हें 64-बिट पर ठीक कर रहा है (बस अगर कोई इसे 32-बिट आर्किटेक्चर पर चलाना चाहता है)।

कुल मिलाकर स्पीडअप x3 और x4 के कारक के बीच है। N = 22 को अभी भी 10 मिनट से कम समय में चलने के लिए आठ से अधिक कोर की आवश्यकता है, लेकिन 64-कोर मशीन पर यह अब लगभग चार मिनट ( numThreadsतदनुसार टकराकर) नीचे है। मुझे नहीं लगता कि एक अलग एल्गोरिथ्म के बिना सुधार के लिए बहुत अधिक जगह है, हालांकि।

एन = 22:

@[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]

फिर से अद्यतन, खोज स्थान में आगे संभव कटौती का उपयोग कर। मेरी क्वाडकोर मशीन पर N = 22 के लिए लगभग 9:49 मिनट में चलता है।

अंतिम अद्यतन (मुझे लगता है)। F के विकल्पों के लिए बेहतर तुल्यता वर्ग, N = 22 के लिए रनटाइम को घटाकर 3:19 मिनट 57 सेकंड (संपादित करें: मैंने गलती से केवल एक धागे से चलाया था)।

यह परिवर्तन इस तथ्य का उपयोग करता है कि वैक्टर की एक जोड़ी एक ही अग्रणी शून्य उत्पन्न करती है यदि एक को घुमाकर दूसरे में परिवर्तित किया जा सकता है। दुर्भाग्य से, एक काफी महत्वपूर्ण निम्न-स्तरीय अनुकूलन की आवश्यकता है कि बिट प्रतिनिधित्व में एफ का शीर्ष बिट हमेशा समान होता है, और इस समानता का उपयोग करते हुए खोज स्थान को काफी कम कर दिया और एक अलग राज्य स्थान का उपयोग करके लगभग एक चौथाई से कम रनटाइम किया F पर कमी, ओवर-लेड ऑप्टिमाइज़ेशन को समाप्त करने से अधिक ओवरहेड इसे ऑफसेट करने से अधिक है। हालांकि, यह पता चला है कि इस समस्या को इस तथ्य से भी समाप्त किया जा सकता है कि एफ एक दूसरे के व्युत्क्रम भी बराबर हैं। जबकि इसने समतुल्यता वर्गों की गणना की जटिलता को थोड़ा जोड़ा, इसने मुझे पूर्वोक्त निम्न-स्तरीय अनुकूलन को बनाए रखने की भी अनुमति दी, जिससे x3 की गति बढ़ गई।

संचित डेटा के लिए 128-बिट पूर्णांक का समर्थन करने के लिए एक और अपडेट। 128 बिट पूर्णांकों के साथ संकलन करने के लिए, आप की आवश्यकता होगी longint.nimसे यहाँ और साथ संकलित करने के लिए -d:use128bit। एन = 24 में अभी भी 10 मिनट से अधिक समय लगता है, लेकिन मैंने नीचे रुचि रखने वालों के लिए परिणाम शामिल किया है।

एन = 24:

@[761152247121980686336, 122682715414070296576, 19793870419291799552, 3193295704340561920, 515628872377565184, 83289931274780672, 13484616786640896, 2191103969198080, 359662314586112, 60521536552960, 10893677035520, 2293940617216, 631498735616, 230983794688, 102068682752, 48748969984, 23993655296, 11932487680, 5955725312, 2975736832, 1487591936, 743737600, 371864192, 185931328, 92965664]

import math, locks, unsigned

when defined(use128bit):
  import longint
else:
  type int128 = uint64 # Fallback on unsupported architectures
  template toInt128(x: expr): expr = uint64(x)

const
  N = 22
  M = N + 1
  FSize = (1 shl N)
  FMax = FSize - 1
  SStep = 1 shl (N-1)
  numThreads = 16

type
  ZeroCounter = array[0..M-1, uint64]
  ZeroCounterLong = array[0..M-1, int128]
  ComputeThread = TThread[int]
  Pair = tuple[value, weight: int32]

var
  leadingZeros: ZeroCounterLong
  lock: TLock
  innerProductTable: array[0..FMax, int8]
  zeroInnerProductList = newSeq[int32]()
  equiv: array[0..FMax, int32]
  fTable = newSeq[Pair]()

proc initInnerProductTables =
  for i in 0..FMax:
    innerProductTable[i] = int8(countBits32(int32(i)) - N div 2)
    if innerProductTable[i] == 0:
      if (i and 1) == 0:
        add(zeroInnerProductList, int32(i))

initInnerProductTables()

proc ror1(x: int): int {.inline.} =
  ((x shr 1) or (x shl (N-1))) and FMax

proc initEquivClasses =
  add(fTable, (0'i32, 1'i32))
  for i in 1..FMax:
    var r = i
    var found = false
    block loop:
      for j in 0..N-1:
        for m in [0, FMax]:
          if equiv[r xor m] != 0:
            fTable[equiv[r xor m]-1].weight += 1
            found = true
            break loop
        r = ror1(r)
    if not found:
      equiv[i] = int32(len(fTable)+1)
      add(fTable, (int32(i), 1'i32))

initEquivClasses()

when defined(gcc):
  const unrollDepth = 4
else:
  const unrollDepth = 4

proc search2(lz: var ZeroCounter, s0, f, w: int) =
  var s = s0
  for i in unrollDepth..M-1:
    lz[i] = lz[i] + uint64(w)
    s = s shr 1
    case innerProductTable[s xor f]
    of 0:
      # s = s + 0
    of -1:
      s = s + SStep
    else:
      return

template search(lz: var ZeroCounter, s, f, w, i: int) =
  when i < unrollDepth:
    lz[i] = lz[i] + uint64(w)
    if i < M-1:
      let s2 = s shr 1
      case innerProductTable[s2 xor f]
      of 0:
        search(lz, s2 + 0, f, w, i+1)
      of -1:
        search(lz, s2 + SStep, f, w, i+1)
      else:
        discard
  else:
    search2(lz, s, f, w)

proc worker(base: int) {.thread.} =
  var lz: ZeroCounter
  for fi in countup(base, len(fTable)-1, numThreads):
    let (fp, w) = fTable[fi]
    let f = if (fp and (FSize div 2)) == 0: fp else: fp xor FMax
    for sp in zeroInnerProductList:
      let s = f xor sp
      search(lz, s, f, w, 0)
  acquire(lock)
  for i in 0..M-1:
    let t = lz[i].toInt128 shl (M-i).toInt128
    leadingZeros[i] = leadingZeros[i] + t
  release(lock)

proc main =
  var threads: array[numThreads, ComputeThread]
  for i in 0 .. numThreads-1:
    createThread(threads[i], worker, i)
  for i in 0 .. numThreads-1:
    joinThread(threads[i])

initLock(lock)
main()
echo(@leadingZeros)

N = 22 के साथ परिणाम 12410090985684467712 है जो 63.42 बिट्स लेता है और इस तरह एक अहस्ताक्षरित 64-बिट में फिट बैठता है।
स्टीफन

2
आपने निश्चित रूप से बार को बहुत प्रभावशाली तरीके से उभारा है।

1
निम्रोद का उपयोग करके किसी को देखने के लिए अच्छा है। :)
cjfaure

@Stefan हो सकता है कि आपकी कोडिंग विजार्ड्री N = 22 के लिए 10 मिनट से कम समय में प्राप्त कर सके?

मैंने N = 22 की कोशिश की, जो कुछ घंटों के बाद समाप्त हो गया। हालांकि यह मुझे देता है [-6036653088025083904, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301,448,822,784, +७१६२०४९३३१२, +२२१००२४६५२८, +८६७६५७३१८४, +३८९७२७८४६४, +१८६०९६०२५६, 911,646,720, 451,520,512, 224,785,920, 112,198,656, 56,062,720, 28,031,360, 14015680] जो एक अतिप्रवाह त्रुटि प्रतीत होती है। मुझे पता है कि कोई निमरॉड नहीं है लेकिन क्या इसे हल करने के लिए अहस्ताक्षरित चींटियों का उपयोग करना संभव है?

11

जावा ( n=22?)

मुझे लगता है कि अधिकांश उत्तर जो n=16इस तरह के दृष्टिकोण का उपयोग करने से बेहतर करते हैं , हालांकि वे उन शोषणों में भिन्न होते हैं जो वे कार्य करते हैं और जिस तरह से वे थ्रेड के बीच कार्य को विभाजित करते हैं।

प्रश्न में परिभाषित वैक्टर को बिट स्ट्रिंग्स के साथ बदल दिया जा सकता है, और आंतरिक उत्पाद XORing के साथ ओवरलैपिंग विंडो और जांच कर सकता है कि वास्तव में n/2बिट्स सेट हैं (और इसलिए n/2बिट्स क्लियर हो गए हैं)। कर रहे हैं n! / ((n/2)!)(केंद्रीय द्विपद गुणांक) के तार nके साथ बिट्स n/2सेट बिट्स (जो मैं फोन संतुलित तार), इसलिए किसी भी के लिए Fवहाँ है कि कई खिड़कियों के हैं Sजो एक शून्य आंतरिक उत्पाद दे। इसके अलावा, Sएक के साथ खिसकने की क्रिया और यह जाँचना कि क्या हम अभी भी एक आने वाली बिट प्राप्त कर सकते हैं जो एक शून्य आंतरिक उत्पाद देता है, एक ग्राफ में एक किनारे की तलाश में है जिसकी नोड्स खिड़कियां हैं और जिनके किनारे नोड uसे एक नोड को जोड़ते हैं vजिसका पहला n-1बिट्स अंतिम हैंn-1के बिट्स u

उदाहरण के लिए, के साथ n=6और F=001001हम इस ग्राफ मिलती है:

F = 001001 के लिए ग्राफ

और F=001011हम इस ग्राफ के लिए:

F = 001011 के लिए ग्राफ

फिर हम प्रत्येक के लिए गिनती करने की आवश्यकता iसे 0करने के लिए nकैसे लंबाई के कई रास्ते i, देखते हैं कि हर के लिए रेखांकन से अधिक संक्षेप F। मुझे लगता है कि हम में से अधिकांश गहराई-पहली खोज का उपयोग कर रहे हैं।

ध्यान दें कि रेखांकन विरल हैं: यह साबित करना आसान है कि प्रत्येक नोड में अधिकतम 1 की डिग्री और अधिकतम एक पर आउट-डिग्री है। इसका मतलब यह भी है कि केवल संभव संरचनाएं सरल चेन और सरल लूप हैं। यह DFS को थोड़ा सरल करता है।

मैं समरूपता के एक जोड़े का शोषण करता हूं: संतुलित तार बिट व्युत्क्रम ( ~ALGOL परिवार से कई भाषाओं में ऑपरेशन) के तहत बंद होते हैं , और बिट रोटेशन के तहत, इसलिए हम एक साथ उन मानों को समूह बना सकते Fहैं जो इन कार्यों से संबंधित हैं और केवल DFS करते हैं एक बार।

public class CodeGolf26459v8D implements Runnable {
    private static final int NUM_THREADS = 8;

    public static void main(String[] args) {
        v8D(22);
    }

    private static void v8D(int n) {
        int[] bk = new int[1 << n];
        int off = 0;
        for (int i = 0; i < bk.length; i++) {
            bk[i] = Integer.bitCount(i) == n/2 ? off++ : -1;
        }

        int[] fwd = new int[off];
        for (int i = 0; i < bk.length; i++) {
            if (bk[i] >= 0) fwd[bk[i]] = i;
        }

        CodeGolf26459v8D[] runners = new CodeGolf26459v8D[NUM_THREADS];
        Thread[] threads = new Thread[runners.length];
        for (int i = 0; i < runners.length; i++) {
            runners[i] = new CodeGolf26459v8D(n, i, runners.length, bk, fwd);
            threads[i] = new Thread(runners[i]);
            threads[i].start();
        }

        try {
            for (int i = 0; i < threads.length; i++) threads[i].join();
        }
        catch (InterruptedException ie) {
            throw new RuntimeException("This shouldn't be reachable", ie);
        }

        long surviving = ((long)fwd.length) << (n - 1);
        for (int i = 0; i <= n; i++) {
            for (CodeGolf26459v8D runner : runners) surviving -= runner.survival[i];
            System.out.print(i == 0 ? "[" : ", ");
            java.math.BigInteger result = new java.math.BigInteger(Long.toString(surviving));
            System.out.print(result.shiftLeft(n + 1 - i));
        }
        System.out.println("]");
    }

    public final int n;
    protected final int id;
    protected final int numRunners;
    private final int[] bk;
    private final int[] fwd;

    public long[] survival;

    public CodeGolf26459v8D(int n, int id, int numRunners, int[] bk, int[] fwd) {
        this.n = n;
        this.id = id;
        this.numRunners = numRunners;

        this.bk = bk;
        this.fwd = fwd;
    }

    private int dfs2(int[] graphShape, int flip, int i) {
        if (graphShape[i] != 0) return graphShape[i];

        int succ = flip ^ (fwd[i] << 1);
        if (succ >= bk.length) succ ^= bk.length + 1;

        int j = bk[succ];
        if (j == -1) return graphShape[i] = 1;

        graphShape[i] = n + 1; // To detect cycles
        return graphShape[i] = dfs2(graphShape, flip, j) + 1;
    }

    @Override
    public void run() {
        int n = this.n;
        int[] bk = this.bk;
        int[] fwd = this.fwd;

        // NB The initial count is approx 2^(2n - 1.33 - 0.5 lg n)
        // For n=18 we overflow 32-bit
        // 64-bit is good up to n=32.
        long[] survival = new long[n + 1];
        boolean[] visited = new boolean[1 << (n - 1)];
        int th = 0;
        for (int f = 0; f < visited.length; f++) {
            if (visited[f]) continue;

            int m = 1, g = f;
            while (true) {
                visited[g] = true;
                int ng = g << 1;
                if ((ng >> (n - 1)) != 0) ng ^= (1 << n) - 1;
                if (ng == f) break;
                m++;
                g = ng;
            }

            if (th++ % numRunners != id) continue;

            int[] graphShape = new int[fwd.length];
            int flip = (f << 1) ^ f;
            for (int i = 0; i < graphShape.length; i++) {
                int life = dfs2(graphShape, flip, i);
                if (life <= n) survival[life] += m;
            }
        }

        this.survival = survival;
    }
}

अपने 2.5GHz Core 2 पर मुझे मिलता है

# n=18
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]

real    0m3.131s
user    0m10.133s
sys     0m0.380s

# n=20
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]

real    1m8.706s
user    4m20.980s
sys     0m0.564s

# n=22
$ javac CodeGolf26459v8D.java && time java CodeGolf26459v8D
[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]

real    20m10.654s
user    76m53.880s
sys     0m6.852s

चूंकि लेम्बिक के कंप्यूटर में 8 कोर हैं और मेरे पहले एकल-थ्रेडेड प्रोग्राम को दो बार तेजी से निष्पादित n=22किया , मैं आशावादी हूं कि यह 8 मिनट से भी कम समय में निष्पादित होगा ।


07:17! बहुत अच्छा। क्या आप अपने तरीके को थोड़ा और समझाएंगे?

6

सी

यह मूल रूप से प्रश्न में एल्गोरिथ्म का केवल थोड़ा अनुकूलित कार्यान्वयन है। यह n=12समय सीमा के भीतर प्रबंधन कर सकता है।

#include <stdio.h>
#include <inttypes.h>

#define n 12
#define m (n + 1)

int main() {
    int i;
    uint64_t S, F, o[m] = {0};
    for (S = 0; S < (1LLU << (n + m - 1)); S += 2)
        for (F = 0; F < (1 << (n - 1)); F++)
            for (i = 0; i < m; i++)
                if (__builtin_popcount(((S >> i) & ((1 << n) - 1)) ^ F) == n >> 1)
                    o[i] += 4;
                else
                    break;
    for (i = 0; i < m; i++)
        printf("%" PRIu64 " ", o[i]);
    return 0;
}

n=12संकलन सहित टेस्ट रन :

$ clang -O3 -march=native -fstrict-aliasing -ftree-vectorize -Wall fast.c
$ time ./a.out 
15502147584 3497066496 792854528 179535872 41181184 9826304 2603008 883712 381952 177920 85504 42560 21280 
real    0m53.266s
user    0m53.042s
sys     0m0.068s
$

टिप्पणी: मैंने सिर्फ अपना दिमाग घुमाया और कुछ साधारण कॉम्बीनेटरिक्स का इस्तेमाल किया ताकि यह गणना की जा सके कि पहला मूल्य हमेशा रहेगा n! / ((n / 2)!)^2 * 2^(n + m - 1)। यह मुझे लगता है कि इस समस्या का पूरी तरह से बीजगणितीय समाधान होना चाहिए।


जब मैं यह संकलन करता हूं तो मुझे बहुत सारी चेतावनियाँ मिलती हैं। Gcc -Wall -Wextra Fors.c -o Fors की कोशिश करें

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

यह Fors.c: 13: 17: चेतावनी के बारे में शिकायत करता है: '&' [-Wparentheses] (दो बार) के ऑपरेंड में '-' के बारे में कोष्ठक का सुझाव दें और यह भी चेतावनी: प्रारूप '% llu' प्रकार के तर्क की अपेक्षा करता है जब तक कि लंबे अहस्ताक्षरित int ', लेकिन तर्क 2 में' uint64_t 'टाइप है [-रूपत =]। वास्तव में

नवीनतम परिवर्तनों के साथ जीसीसी को कोई चेतावनी संदेश नहीं फेंकना चाहिए।
फोर्स

यह अभी भी Fors.c: 13: 49: चेतावनी के बारे में शिकायत करता है: '^' [-Wparentheses] के संचालन में अंकगणित के चारों ओर कोष्ठक का सुझाव दें, लेकिन बदतर समाचारों में ... मेरी मशीन पर 10 मिनट से अधिक समय लगता है।

5

जावा, n=16

किसी भी मूल्य के Fलिए \binom{n}{n/2}वैक्टर होते हैं जिनके पास एक शून्य आंतरिक उत्पाद होता है। तो हम एक ग्राफ बना सकते हैं, जिसका सिरा उन मिलान वाले वैक्टर और जिनके किनारों के स्थानांतरण के अनुरूप हैं S, और फिर हमें केवल nग्राफ़ में लंबाई के पथ को गिनने की आवश्यकता है ।

मैंने बिटवाइज़ ऑपरेशंस के साथ कंडीशन को बदलकर इसे अपनाने की कोशिश नहीं की है, लेकिन प्रत्येक डबल-इन्क्रीमेंट है n रनिंग टाइम के बारे में 16 गुना बढ़ जाता है, इसलिए जब तक मैं थ्रेसहोल्ड के बहुत करीब नहीं होता, तब तक बहुत फर्क नहीं पड़ता। मेरी मशीन पर, मैं नहीं।

public class CodeGolf26459 {

    public static void main(String[] args) {
        v3(16);
    }

    // Order of 2^(2n-1) * n ops
    private static void v3(int n) {
        long[] counts = new long[n+1];
        int mask = (1 << n) - 1;
        for (int f = 0; f < (1 << (n-1)); f++) {
            // Find adjacencies
            long[] subcounts = new long[1 << n];
            for (int g = 0; g < (1 << n); g++) {
                subcounts[g] = Integer.bitCount(f ^ g) == n/2 ? 2 : -1;
            }

            for (int round = 0; round <= n; round++) {
                long count = 0;
                // Extend one bit.
                long[] next = new long[1 << n];
                for (int i = 0; i < (1 << n); i++) {
                    long s = subcounts[i];
                    if (s == -1) next[i] = -1;
                    else {
                        count += s;
                        int j = (i << 1) & mask;
                        if (subcounts[j] >= 0) next[j] += s;
                        if (subcounts[j + 1] >= 0) next[j + 1] += s;
                    }
                }
                counts[round] += count << (n - round);
                subcounts = next;
            }
        }

        System.out.print("[");
        for (long count : counts) System.out.print(count+", ");
        System.out.println("]");
    }
}

अपने 2.5GHz Core 2 पर मुझे मिलता है

$ javac CodeGolf26459.java && time java -server CodeGolf26459 
[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600, ]

real    6m2.663s
user    6m4.631s
sys     0m1.580s

पिग्गीबैकिंग के बाद से मैं अभी अपने समाधान को लागू नहीं करना चाहता। प्रत्येक शीर्ष पर सबसे अधिक एक उत्तराधिकारी है, इसलिए आपको वास्तव में सरणी की आवश्यकता नहीं है। कुशलता से संयोजन के लिए fऔर खड़ी शुरू करने पर, f_xor_gबिल्कुल n/2सेट बिट्स के साथ पुनरावृति । इनमें से प्रत्येक के लिए, सभी पर पुनरावृति fऔर ले g = f ^ f_xor_g
डेविड आइसेनस्टैट

@ डेविड, मुझे पता है, और मेरा संस्करण 7 मेरी एटम नेटबुक पर एक मिनट में n = 18 करता है, लेकिन मैं इसे तब तक पोस्ट नहीं कर सकता जब तक मैं छुट्टी से वापस नहीं आता।
पीटर टेलर

4

आरपीथॉन, एन = 22 ~ 3: 23

बहु-थ्रेडेड, एक स्टैकलेस पुनरावर्ती वंश का उपयोग करते हुए। कार्यक्रम दो कमांड लाइन तर्क स्वीकार करता है: एन, और कार्यकर्ता थ्रेड्स की संख्या।

from time import sleep

from rpython.rlib.rthread import start_new_thread, allocate_lock
from rpython.rlib.rarithmetic import r_int64, build_int, widen
from rpython.rlib.rbigint import rbigint

r_int8 = build_int('r_char', True, 8)

class ThreadEnv:
  __slots__ = ['n', 'counts', 'num_threads',
               'v_range', 'v_num', 'running', 'lock']

  def __init__(self):
    self.n = 0
    self.counts = [rbigint.fromint(0)]
    self.num_threads = 0
    self.v_range = [0]
    self.v_num = 0
    self.running = 0
    self.lock = None

env = ThreadEnv()

bt_bits = 12
bt_mask = (1<<bt_bits)-1
# computed compile time
bit_table = [r_int8(0)]
for i in xrange(1,1<<bt_bits):
  bit_table += [((i&1)<<1) + bit_table[i>>1]]

def main(argv):
  argc = len(argv)
  if argc < 2 or argc > 3:
    print 'Usage: %s N [NUM_THREADS=2]'%argv[0]
    return 1

  if argc == 3:
    env.num_threads = int(argv[2])
  else:
    env.num_threads = 2

  env.n = int(argv[1])
  env.counts = [rbigint.fromint(0)]*env.n
  env.lock = allocate_lock()

  v_range = []
  v_max = 1<<(env.n-1)
  v_num = 0
  v = (1<<(env.n>>1))-1
  while v < v_max:
    v_num += 1
    v_range += [v]
    if v&1:
      # special case odd v
      s = (v+1)&-v
      v ^= s|(s>>1)
    else:
      s = v&-v
      r = v+s
      # s is at least 2, skip two iterations
      i = 3
      s >>= 2
      while s:
        i += 1
        s >>= 1
      v = r|((v^r)>>i)
  env.v_range = v_range
  env.v_num = v_num

  for i in xrange(env.num_threads-1):
    start_new_thread(run,())

  # use the main process as a worker
  run()

  # wait for any laggers
  while env.running:
    sleep(0.05)

  result = []
  for i in range(env.n):
    result += [env.counts[i].lshift(env.n-i+3).str()]
  result += [env.counts[env.n-1].lshift(3).str()]
  print result
  return 0

def run():
  with env.lock:
    v_start = env.running
    env.running += 1

  n = env.n
  counts = [r_int64(0)]*n
  mask = (1<<n)-1
  v_range = env.v_range
  v_num = env.v_num
  z_count = 1<<(n-2)

  for i in xrange(v_start, v_num, env.num_threads):
    v = v_range[i]
    counts[0] += z_count
    counts[1] += v_num
    r = v^(v<<1)
    for w in v_range:
      # unroll counts[2] for speed
      # ideally, we could loop over x directly,
      # rather than over all v, only to throw the majority away
      # there's a 2x-3x speed improvement to be had here...
      x = w^r
      if widen(bit_table[x>>bt_bits]) + widen(bit_table[x&bt_mask]) == n:
        counts[2] += 1
        x, y = v, x
        o, k = 2, 3
        while k < n:
          # x = F ^ S
          # y = F ^ (S<<1)
          o = k
          z = (((x^y)<<1)^y)&mask
          # z is now F ^ (S<<2), possibly xor 1
          # what S and F actually are is of no consequence

          # the compiler hint `widen` let's the translator know
          # to store the result as a native int, rather than a signed char
          bt_high = widen(bit_table[z>>bt_bits])
          if bt_high + widen(bit_table[z&bt_mask]) == n:
            counts[k] += 1
            x, y = y, z
            k += 1
          elif bt_high + widen(bit_table[(z^1)&bt_mask]) == n:
            counts[k] += 1
            x, y = y, z^1
            k += 1
          else: k = n

  with env.lock:
    for i in xrange(n):
      env.counts[i] = env.counts[i].add(rbigint.fromrarith_int(counts[i]))
    env.running -= 1

def target(*args):
  return main, None

संकलन करना

पारा , गिट, या जो भी आप पसंद करते हैं, का उपयोग करके PyPy रिपॉजिटरी का एक स्थानीय क्लोन बनाएं । निम्नलिखित अभिसरण टाइप करें (उपरोक्त स्क्रिप्ट का नाम दिया गया है convolution-high.py):

$ pypy %PYPY_REPO%/rpython/bin/rpython --thread convolution-high.py

%PYPY_REPO%एक पर्यावरण चर का प्रतिनिधित्व करता है, जहां आप सिर्फ क्लोन किए गए भंडार की ओर इशारा करते हैं। संकलन में लगभग एक मिनट लगता है।


नमूना समय

एन = 16, 4 धागे:

$ timeit convolution-high-c 16 4
[55276229099520, 10855179878400, 2137070108672, 420578918400, 83074121728, 16540581888, 3394347008, 739659776, 183838720, 57447424, 23398912, 10749184, 5223040, 2584896, 1291424, 645200, 322600]
Elapsed Time:     0:00:00.109
Process Time:     0:00:00.390

एन = 18, 4 धागे:

$ timeit convolution-high-c 18 4
[3341140958904320, 619683355033600, 115151552380928, 21392898654208, 3982886961152, 744128512000, 141108051968, 27588886528, 5800263680, 1408761856, 438001664, 174358528, 78848000, 38050816, 18762752, 9346816, 4666496, 2333248, 1166624]
Elapsed Time:     0:00:01.250
Process Time:     0:00:04.937

एन = 20, 4 धागे:

$ timeit convolution-high-c 20 4
[203141370301382656, 35792910586740736, 6316057966936064, 1114358247587840, 196906665902080, 34848574013440, 6211866460160, 1125329141760, 213330821120, 44175523840, 11014471680, 3520839680, 1431592960, 655872000, 317675520, 156820480, 78077440, 39005440, 19501440, 9750080, 4875040]
Elapsed Time:     0:00:15.531
Process Time:     0:01:01.328

एन = 22, 4 धागे:

$ timeit convolution-high-c 22 4
[12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]
Elapsed Time:     0:03:23.156
Process Time:     0:13:25.437

09:26। 22 क्रू में आपका स्वागत है :)

मुझे यकीन नहीं है कि क्यों लेकिन आपका नया संस्करण मेरे लिए अधिक तेज़ नहीं है। अभी भी 9:30 के बारे में जब मैं समय करता हूं ।/primo-c 22 8।

@ लिम्बिक से यह समझ में आएगा कि यदि विभाजन लगभग 3 सही बदलावों (3 = Sum {(n + 1) / / (2 ^ n)}, n = 1..infty) के रूप में तेजी से होता है। सर्टिफिकेट आर्किटेक्चर के लिए, मुझे लगता है कि ऐसा हो सकता है, लेकिन खदान विभाजन पर यह काफी धीमा है। इसका परीक्षण करने के लिए समय निकालने के लिए धन्यवाद :)
प्रथम

3

पायथन 3.3, एन = 20, 3.5 मिनट

डिस्क्लेमर: मेरा इरादा इसे अपने उत्तर के रूप में पोस्ट करने का नहीं है, क्योंकि मैं जिस एल्गोरिथ्म का उपयोग कर रहा हूं वह प्राइमो के आरपीथॉन समाधान से केवल एक बेशर्म पोर्ट है । यहां मेरा उद्देश्य केवल यह दिखाना है कि यदि आप नम्पी और नंबा मॉड्यूल के जादू को जोड़ते हैं तो आप पायथन में क्या कर सकते हैं ।

निम्बा ने संक्षेप में समझाया:

Numba एक समय-समय पर विशेषज्ञता वाला कंपाइलर है जो Python और NumPy कोड को LLVM (डेकोरेटर्स के माध्यम से) में संकलित करता है। http://numba.pydata.org/

अद्यतन 1 : मैंने देखा कि आस-पास की संख्याओं को उछालने के बाद हम केवल कुछ संख्याओं को पूरी तरह से छोड़ सकते हैं। तो अब maxf बन जाता है (1 << n) // 2 और maxs बन जाता है maxf 2 **। यह प्रक्रिया को काफी तेज कर देगा। n = 16 अब केवल ~ 48s (4,5min से नीचे) लेता है। मेरे पास एक और विचार है जो मैं कोशिश करने जा रहा हूं और देख सकता हूं कि क्या मैं इसे थोड़ा तेज कर सकता हूं।

अद्यतन 2: परिवर्तित एल्गोरिथ्म (प्राइमो का समाधान)। हालांकि मेरा पोर्ट अभी तक मल्टीथ्रेडिंग का समर्थन नहीं करता है लेकिन इसे जोड़ना बहुत ही मामूली है। Numba और ctypes का उपयोग करके CPython GIL को रिलीज़ करना संभव है। यह समाधान, हालांकि, सिंगल कोर पर बहुत तेजी से चलता है!

import numpy as np
import numba as nb

bt_bits = 11
bt_mask = (1 << bt_bits) - 1
bit_table = np.zeros(1 << bt_bits, np.int32)

for i in range(0, 1 << bt_bits):
    bit_table[i] = ((i & 1) << 1) + bit_table[i >> 1]

@nb.njit("void(int32, int32, int32, int32, int64[:], int64[:])")
def run(n, m, start, re, counts, result):
    mask = (1 << n) - 1

    v_max = (1 << n) // 2
    rr = v_max // 2

    v = (1 << (n >> 1)) - 1
    while v < v_max:
        s = start

        while s < rr:
            f = v ^ s
            counts[0] += 8
            t = s << 1
            o, j = 0, 1

            while o < j and j < m:
                o = j
                w = (t ^ f) & mask
                bt_high = bit_table[w >> bt_bits]

                if bt_high + bit_table[w & bt_mask] == n:
                    counts[j] += 8
                    t <<= 1
                    j += 1
                elif bt_high + bit_table[(w ^ 1) & bt_mask] == n:
                    counts[j] += 8
                    t = (t | 1) << 1
                    j += 1
                    s += re

            s = v & -v
            r = v + s
            o = v ^ r
            o = (o >> 2) // s
            v = r | o

    for e in range(m):
        result[e] += counts[e] << (n - e)

और अंत में:

if __name__ == "__main__":
    n = 20
    m = n + 1

    result = np.zeros(m, np.int64)
    counts = np.zeros(m, np.int64)

    s1 = time.time() * 1000
    run(n, m, 0, 1, counts, result)
    s2 = time.time() * 1000

    print(result)
    print("{0}ms".format(s2 - s1))

यह 212688ms या ~ 3.5min में मेरी मशीन पर चलता है।


धन्यवाद। अब n = 18 के बारे में कैसे? :)

जब से मैंने n = 18 का उपयोग करके कार्यक्रम शुरू किया है, तब से यह लगभग 20min हो गया है। मुझे लगता है कि यह कहना सुरक्षित है कि पायथन इस समय को Numba के साथ भी हल नहीं कर सकता है इस विशेष एल्गोरिथ्म का उपयोग करके।
अन्ना जोकेला

मैं आशावादी हूं कि एक बेहतर एल्गोरिथ्म मौजूद है।

मैं पाइप सुंबा स्थापित करने की कोशिश की, लेकिन यह कहते हैं कि यह llvmpy नहीं मिल सकता है। मैंने sudo pip को llvmpy स्थापित करने की कोशिश की, लेकिन यह कहता है कि यह वर्जन नहीं पा सकता है। मैं sudo पाइप स्थापित संस्करण की कोशिश की, लेकिन यह कहते हैं कि मैं पहले से ही यह है।

हालांकि मुझे अभी तक काम करने के लिए सुब्बा नहीं मिला है (मुझे लगता है कि मुझे अंत में एनाकोंडा स्थापित करना होगा) मैं इससे प्रभावित हूं। सवाल यह है कि क्या आप निमरॉड एक समान विधि का उपयोग करके एन = 22 को हल करने के लिए प्राप्त कर सकते हैं?

2

सी ++ एन = 16

मैं एक परमाणु के साथ एक EEEPC पर परीक्षण कर रहा हूँ .. मेरा समय समझ में नहीं आता है। : D
परमाणु 34 सेकंड में n = 14 को हल करता है। और 20 मिनट में n = 16। मैं ओपी पीसी पर n = 16 का परीक्षण करना चाहता हूं। मैं आशावादी हूं।

विचार यह है कि हर बार जब हम किसी दिए गए एफ के लिए समाधान ढूंढते हैं तो हमें 2 ^ i समाधान मिल जाता है क्योंकि हम S के निचले हिस्से को उसी परिणाम में बदल सकते हैं।

#include <stdio.h>
#include <cinttypes>
#include <cstring>

int main()
{
   const int n = 16;
   const int m = n + 1;
   const uint64_t maxS = 1ULL << (2*n);
   const uint64_t maxF = 1ULL << n;
   const uint64_t mask = (1ULL << n)-1;
   uint64_t out[m]={0};
   uint64_t temp[m] = {0};
   for( uint64_t F = 0; F < maxF; ++F )
   {
      for( uint64_t S = 0; S < maxS; ++S )
      {
         int numSolution = 1;
         for( int i = n; i >= 0; --i )
         {
            const uint64_t window = S >> i;
            if( __builtin_popcount( mask & (window ^ F) ) == (n / 2) )
            {
               temp[i] += 1;
            } else {
               numSolution = 1 << i;
               S += numSolution - 1;
               break;
            }
         }
         for( int i = n; i >= 0; --i )
         {
            out[i] += temp[i]*numSolution;
            temp[i] = 0;
         }
      }
   }
   for( int i = n; i >= 0; --i )
   {
      uint64_t x = out[i];
      printf( "%lu ", x );
   }
   return 0;
}

संकलन करना:

gcc 26459.cpp -std = c ++ 11 -O3 -Mchch = देशी -फ्रस्ट्रिक्ट-अलियासिंग -ftree-वेक्टर -Wall -pedantic -o 26459


1
यह भी खूब रही। वास्तव में मेरे पास कुछ आधे बेक्ड विचार हैं कि इसे बड़े एन के लिए कैसे हल किया जाए। क्या आप उन्हें सुनना चाहेंगे या प्रतियोगिता को खराब कर सकते हैं?

2

JAVASCRIPT n: 12

मेरे कंप्यूटर में इसे 231.242 सेकंड का समय लगा। ब्राउज़र में मैं ब्राउज़र को फ्रीज़ करने से रोकने के लिए वेबवर्क का उपयोग कर रहा हूँ। समानांतर श्रमिकों के साथ यह सुनिश्चित किया जा सकता है कि इसे और बेहतर बनाया जा सके। मैं जानता हूँ कि जेएस इस चुनौती में एक मौका नहीं है लेकिन मैंने इसे मज़े के लिए किया है!

ऑनलाइन डेमो चलाने के लिए क्लिक करें

var n = 8;        
var m = n + 1;
var o = [];
var popCount = function(bits) {
  var SK5  = 0x55555555,
      SK3  = 0x33333333,
      SKF0 = 0x0f0f0f0f,
      SKFF = 0xff00ff;

  bits -= (bits >> 1) & SK5;
  bits  = (bits & SK3) + ((bits >> 2) & SK3);
  bits  = (bits & SKF0) + ((bits >> 4) & SKF0);
  bits += bits >> 8;

  return (bits + (bits >> 15)) & 63;
};
for(var S = 0; S < (1 << n + m - 1); S += 2){
  for(var F = 0; F < (1 << n - 1); F += 1){
    for (var i = 0; i < m; i++){
      var c = popCount(((S >> i) & ((1 << n) - 1)) ^ F);
      if(c == n >> 1){
        if(!o[i]) o[i] = 0;
        o[i] += 4;
      } else break;
    }
  }
}
return o;

उन नए (ईश) फास्ट जावास्क्रिप्ट इंजनों में से एक के बारे में क्या? क्या उन का उपयोग किया जा सकता है?

आप डार्ट की तरह कुछ मतलब है ?
राफेलकास्ट्रोक्टो

1
वास्तव में मैं गलत हूं। तुम भी बस फ़ायरफ़ॉक्स और क्रोमियम दोनों की कोशिश कर सकते हैं। जब तक आप इसे asm.js of course में लिखना नहीं चाहते हैं :)

1
चुनौती स्वीकार की ... यह करने जा रहे हैं!
राफेलकास्ट्रोकोटो

1
इस की कोशिश की और अपने कंप्यूटर को 5.4 सेकंड में कर लिया n=22 [235388928,86292480,19031048,5020640,1657928,783920,545408,481256,463832,460256,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744,459744] i.imgur.com/FIJa2Ch.png
Spedwards

1

फोरट्रान: एन = 12

मैंने अभी फोरट्रान में क्विक'डाइनहाइट संस्करण बनाया है, ओपनएमपी को छोड़कर कोई अनुकूलन नहीं। यह ओपीएस मशीन पर n = 12 के लिए बस 10 मिनट से कम समय में निचोड़ना चाहिए, यह मेरी मशीन पर 10:39 लेता है जो कि धीमी गति से धीमा है।

64-बिट पूर्णांक वास्तव में एक नकारात्मक प्रदर्शन प्रभाव है; लगता है कि मैं बहुत तेजी से होने के लिए पूरे एल्गोरिथ्म पर पुनर्विचार करना होगा। नहीं जानता कि क्या मैं परेशान होने जा रहा हूं, मुझे लगता है कि मैं कुछ समय बिताने के लिए एक अच्छी चुनौती सोचता हूं जो मेरे अपने स्वाद के लिए अधिक है। अगर कोई और इसे लेना चाहता है और इसके साथ चलना चाहता है, तो आगे बढ़ें :)

program golf
use iso_fortran_env
implicit none
integer, parameter ::  n=12
integer :: F(n), S(2*n)
integer(int64) :: leadingzerocounts(n+1)
integer :: k
integer(int64) :: i,j,bindec,enc

leadingzerocounts=0

!$OMP parallel do private(i,enc,j,bindec,S,F,k) reduction(+:leadingzerocounts) schedule(dynamic)
do i=0,2**(2*n)-1
  enc=i
  ! Short loop to convert i into the array S with -1s and 1s
  do j=2*n,1,-1
    bindec=2**(j-1)
    if (enc-bindec .ge. 0) then
      S(j)=1
      enc=enc-bindec
    else
      S(j)=-1
    endif
  end do
  do j=0,2**(n)-1
    ! Convert j into the array F with -1s and 1s
    enc=j
    do k=n,1,-1
      bindec=2**(k-1)
      if (enc-bindec .ge. 0) then
        F(k)=1
        enc=enc-bindec
      else
        F(k)=-1
      endif
    end do
    ! Compute dot product   
    do k=1,n+1
      if (dot_product(F,S(k:k+n-1)) /= 0) exit
      leadingzerocounts(k)=leadingzerocounts(k)+1
    end do
  end do
end do
!$OMP end parallel do

print *, leadingzerocounts

end

1

लुआ: n = 16

डिस्क्लेमर: मेरा इरादा इसे अपने उत्तर के रूप में पोस्ट करने का नहीं है, क्योंकि मैं जिस एल्गोरिथ्म का उपयोग कर रहा हूं वह बेशर्मी से अन्ना जोकेला के चतुर उत्तर से चोरी हो गया है । जो बेशर्मी से इल्मले के चतुर जवाब से चुरा लिया गया था ।

इसके अलावा, यह भी मान्य नहीं है - इसमें फ्लोटिंग पॉइंट नंबरों के कारण होने वाली अशुद्धि है (यह बेहतर होगा कि Lua 64-बिट पूर्णांक का समर्थन करेगा)। हालाँकि, मैं अभी भी इसे अपलोड कर रहा हूँ, बस यह दिखाने के लिए कि यह समाधान कितना तेज़ है। यह एक गतिशील प्रोग्रामिंग भाषा है, और फिर भी मैं उचित समय में n = 16 की गणना कर सकता हूं (800 मेगाहर्ट्ज सीपीयू पर 1 मिनट)।

LuaJIT के साथ चलाएँ, मानक दुभाषिया बहुत धीमा है।

local bit = require "bit"
local band = bit.band
local bor = bit.bor
local bxor = bit.bxor
local lshift = bit.lshift
local rshift = bit.rshift

-- http://stackoverflow.com/a/11283689/736054
local function pop_count(w)
    local b1 = 1431655765
    local b2 = 858993459
    local b3 = 252645135
    local b7 = 63

    w = band(rshift(w, 1), b1) + band(w, b1)
    w = band(rshift(w, 2), b2) + band(w, b2)
    w = band(w + rshift(w, 4), b3)
    return band(rshift(w, 24) + rshift(w, 16) + rshift(w, 8) + w, b7)
end

local function gen_array(n, value)
    value = value or 0
    array = {}
    for i = 1, n do
        array[i] = value
    end
    return array
end

local n = 16
local u = math.floor(n / 2)
local m = n + 1
local maxf = math.floor(lshift(1, n) / 2)
local maxs = maxf ^ 2
local mask = lshift(1, n) - 1

local out = gen_array(m, 0)
local temp = gen_array(m, 0)


for f = 0, maxf do
    local s = 0
    while s <= maxs do
        local num_solution = 1

        for i = n, 0, -1 do
            if pop_count(band(mask, bxor(rshift(s, i), f))) == u then
                temp[i + 1] = temp[i + 1] + 8
            else
                num_solution = lshift(1, i)
                s = s + num_solution - 1
                break
            end
        end

        for i = 1, m do
            out[i] = out[i] + temp[i] * num_solution
            temp[i] = 0
        end

        s = s + 1
    end
end

for i = m, 1, -1 do
    print(out[i])
end

धन्यवाद। मुझे लगता है कि हालिया लुआ संस्करण लंबे लंबे इंट का उपयोग करते हैं जो 64 बिट सिस्टम पर 64 बिट होना चाहिए। पर "lua_integer" देखें lua.org/work/doc/manual.html

@ लिम्बिक: दिलचस्प। किसी भी तरह से, यह मानक Lua है (जो पहले long longसे doubleही एक संकलन सेटिंग के बजाय समर्थन करता है ), LuaJIT नहीं।
कोनराड बोरोस्की

मुझे लगता है कि मैं किसी भी मामले में गलत था luajit। किसी को 5.3 की आवश्यकता होगी जो मौजूद नहीं है। सबसे अच्छी सलाह लूआ लोग दे सकते थे "कोशिश 5.3-वर्कएक्स"।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.