কিভাবে উচ্চ আপনি যেতে পারেন? (একটি কোডিং + অ্যালগোরিদম চ্যালেঞ্জ)


34

এখন যেহেতু প্রত্যেকে তাদের (প্রায়শই আশ্চর্যজনক) নিম্ন স্তরের কোডিং দক্ষতা গড়ে তুলেছে তার জন্য পাইথনটি আসলে কত ধীর? (বা আপনার ভাষাটি কত গতিযুক্ত ?) এবং পাইথন সত্যই কত ধীর (দ্বিতীয় খণ্ড)? এটি এখন একটি চ্যালেঞ্জের জন্য সময় যা অ্যালগোরিদমকে উন্নত করার আপনার ক্ষমতাও প্রসারিত করবে।

নিম্নলিখিত কোড 9. অবস্থান দৈর্ঘ্য একটি তালিকা নির্ণয় iতালিকায় অন্তত যতবার বড়, মোট ছাত্র iপরপর শূন্য মধ্যে ভেতরের পণ্য কম্পিউটিং যখন খুঁজে পাওয়া যায়নি Fএবং S। এই ঠিক করার জন্য, এটা সব সম্ভব তালিকা উপর iterates 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]

আপনি যদি এই কোডটি ব্যবহার করে এনটি 10,12,14,16,18,20 এ বৃদ্ধি করেন তবে এটি খুব দ্রুত খুব ধীর হয়ে যায়।

বিধি

  • চ্যালেঞ্জটি হ'ল যথাসম্ভব বৃহত্তর এন এর জন্য সঠিক আউটপুট দেওয়া। কেবলমাত্র n এর মানগুলিও প্রাসঙ্গিক।
  • যদি কোনও টাই থাকে, তবে বিজয়টি সবচেয়ে বড় এন এর জন্য আমার মেশিনের দ্রুততম কোডে যায়।
  • আমি 10 মিনিটের বেশি সময় লাগে এমন কোডটি পরীক্ষা না করার অধিকার সংরক্ষণ করি।
  • আপনি সঠিকভাবে আউটপুট দেয় যতক্ষণ না আপনি পছন্দ মতো কোনওভাবেই অ্যালগরিদম পরিবর্তন করতে পারেন। আসলে আপনাকে জয়ের দিকে কোনও উন্নত অগ্রগতি করতে অ্যালগরিদম পরিবর্তন করতে হবে
  • প্রশ্নটি নির্ধারিত হওয়ার পর থেকে বিজয়ীকে এক সপ্তাহ পুরষ্কার দেওয়া হবে।
  • অনুগ্রহকারীদের যখন প্রদান করা হয় তখন পুরষ্কার দেওয়া হবে যা বিজয়ীর পুরষ্কার দেওয়া হবে তার একটু পরে।

আমার মেশিন সময়গুলি আমার মেশিনে চালিত হবে। এটি একটি এএমডি এফএক্স-8350 এইট-কোর প্রসেসরে একটি স্ট্যান্ডার্ড উবুন্টু ইনস্টল। এর অর্থ হল আপনার কোডটি চালাতে আমার সক্ষম হওয়া দরকার। ফলস্বরূপ, কেবল সহজেই উপলভ্য নিখরচায় সফ্টওয়্যার ব্যবহার করুন এবং দয়া করে আপনার কোডটি কীভাবে সংকলন করতে এবং চালাতে হয় তার সম্পূর্ণ নির্দেশাবলী অন্তর্ভুক্ত করুন।

স্থিতি

  • । @ = দ্বারা 49 সেকেন্ডে এন = 12
  • জাভা । @ = পিটারটেলর দ্বারা 3:07 এ এন = 16
  • সি ++ । @ = 2 দ্বারা 2 = 21 এ এন = 16
  • Rpython । n = 22 3:11 এ @ প্রিয়মো দ্বারা
  • জাভা । @ পিটারটেলর দ্বারা 6:56 এ এন = 22
  • নিমরোড । @ রিমারব্রেইন্ডস দ্বারা 9:28 সেকেন্ডে এন = 24

বিজয়ী ছিলেন নিমরোডে এন্ট্রি নিয়ে রিমার বেহরেন্ডস!

চেক হিসাবে, এন = 22 এর আউটপুট হওয়া উচিত [12410090985684467712, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680]


প্রতিযোগিতাটি এখন শেষ কিন্তু ... আমি পয়েন্ট ছাড়াই যতক্ষণ না 2 (আমার কম্পিউটারে 10 মিনিটের মধ্যে) 2 বৃদ্ধি পাবে এমন প্রতিটি জমা দেওয়ার জন্য 200 পয়েন্ট অফার করব । এই অফার চিরকালের জন্য উন্মুক্ত ।


1
"আমি কোডটি পরীক্ষা না করার অধিকার সংরক্ষণ করি যা কয়েক মিনিটেরও বেশি সময় নেয়।" > আপনার মেশিনে আপনার একটি সঠিক সময় নির্দিষ্ট করা উচিত, অন্যথায় এই প্রশ্নের উদ্দেশ্যমূলক বিজয়ী মানদণ্ডের অভাব হবে।
পেস্টবিন.কম 0mr8spkT

14
আমি এইগুলিকে "আমার গতি বৃদ্ধি" চ্যালেঞ্জগুলি পছন্দ করি love আপনি যদি এগুলি দিয়ে বাণিজ্যিক পণ্য তৈরি করে থাকেন তবে আপনার কাছে দ্রুত পণ্যটির একটি নরক রয়েছে, এবং আপনি একজন দুষ্টু প্রতিভাও
রেইনবোল্ট

1
সম্ভবত আরও একটি তথ্যবহুল শিরোনাম এটি মনোযোগ আকর্ষণ করবে?
TheDoctor

8
যদি আমরা এই ধরণের চ্যালেঞ্জটি চালিয়ে যাই তবে আমি মনে করি আমাদের কমপক্ষে একটি আকর্ষণীয় রাখার জন্য আলাদা সমস্যা সমাধানের চেষ্টা করা উচিত (অতিরিক্ত স্পেসিফিকেশনের সাথে একই সমস্যার কোনও প্রকরণ নয়)।
গ্রোভস এনএল

2
@ ক্লাউডিউ তার সিপিইউতে 8 টি শারীরিক কোর রয়েছে তবে আনয়ন / ডিকোড এবং এফপিইউ ইউনিটগুলি কোরগুলির মধ্যে ভাগ করা রয়েছে। সুতরাং যখন বাধাগুলি সেই অঞ্চলগুলির একটিতে থাকে, তখন এটি চতুষ্কোণীর মতো আচরণ করে। পূর্ণ সংখ্যার যুক্তিকে আপত্তিজনক ব্যবহার করুন এবং বড় কোডের আকারগুলি এড়ান এবং এটি আরও 8-কোরের মতো।
স্টিফান

উত্তর:


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 মিনিট সময় নেয়) time

অ্যালগরিদম একটি পুনরাবৃত্ত অনুসন্ধান অনুসন্ধান করে, যখনই কোনও শূন্য-অভ্যন্তরীণ পণ্যটির মুখোমুখি হয় তখন অনুসন্ধান গাছকে ছাঁটাই করে। যে কোনও ভেক্টর জোড়ের জন্য পর্যবেক্ষণ করে আমরা অনুসন্ধানের স্থানটি অর্ধেকে কেটে ফেলেছি(F, -F) আমাদের কেবল একটি বিবেচনা করা দরকার কারণ অন্যটি অভ্যন্তরীণ পণ্যের সঠিক একই সেট তৈরি করে (উপেক্ষা করে)S এছাড়াও )।

পুনরাবৃত্ত অনুসন্ধানের প্রথম কয়েক স্তরের তালিকাটি আনرول / ইনলাইন করতে নিম্রোডের রূপক সুবিধাগুলি প্রয়োগ করা হয়। নিম্রোডের ব্যাকএন্ড এবং ঝাঁকুনির জন্য মোটামুটি পরিমাণ হিসাবে জিসিসি 4.8 এবং 4.9 ব্যবহার করার সময় এটি অল্প সময় সাশ্রয় করে।

অনুসন্ধানের স্থানটি পর্যবেক্ষণ করে আরও ছাঁটাই করা যেতে পারে যে আমাদের কেবলমাত্র এস এর মানগুলি বিবেচনা করা দরকার যা আমাদের পছন্দ হিসাবে আমাদের প্রথম পছন্দ হিসাবে এন এর প্রথম সংখ্যাগুলির মধ্যে পৃথক হয়। তবে, এর জটিলতা বা মেমরির প্রয়োজনগুলি বড় মানগুলির জন্য স্কেল করে না এন এর, প্রদত্ত যে লুপ বডি পুরোপুরি এই ক্ষেত্রে বাদ দেওয়া হয়।

অভ্যন্তরীণ পণ্যটি শূন্য যেখানে সারণীটি লুপটিতে কোনও বিট গণনা কার্যকারিতা ব্যবহারের চেয়ে দ্রুত বলে মনে হয়। স্পষ্টত টেবিল অ্যাক্সেস বেশ ভাল লোকেশন আছে।

দেখে মনে হচ্ছে সমস্যাটি ডাইনামিক প্রোগ্রামিংয়ের জন্য উপযুক্ত হতে হবে, এটি পুনরাবৃত্ত অনুসন্ধানগুলি কীভাবে কাজ করে তা বিবেচনা করে, তবে যুক্তিসঙ্গত পরিমাণ মেমরির সাথে এটি করার কোনও আপাত উপায় নেই।

উদাহরণ ফলাফল:

এন = 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]

অন্যান্য বাস্তবায়নের সাথে অ্যালগরিদমের তুলনা করার উদ্দেশ্যে, এন সিটেন 16 মেশিনে প্রায় 7.9 সেকেন্ড সময় নেয় যখন একটি একক থ্রেড ব্যবহার করে এবং 2.4 সেকেন্ড চারটি কোর ব্যবহার করার সময়।

নিম = 224-তে জি.সি.সি. ৪.৪. with সহ একটি -৪-কোর মেশিনে প্রায় 15 মিনিট সময় নেয় এবং inte৪-বিট পূর্ণসংখ্যায় ওভারফ্লো হয় leadingZeros[0](সম্ভবত স্বাক্ষরযুক্ত নয়, এটির দিকে নজর দেয়নি)।


আপডেট: আমি আরও কয়েকটি উন্নতির জন্য জায়গা পেয়েছি। প্রথমত, প্রদত্ত মানের জন্য F, আমরা সংশ্লিষ্ট Sভেক্টরগুলির প্রথম 16 টি এন্ট্রিগুলিকে যথাযথভাবে গণনা করতে পারি , কারণ তাদের অবশ্যই ঠিক N/2জায়গায় পৃথক হতে হবে । সুতরাং আমরা আকারের বিট ভেক্টর একটি তালিকা precompute Nআছে N/2বিট সেট এবং প্রারম্ভিক অংশ আহরণ করতে এগুলি ব্যবহার SথেকেF

দ্বিতীয়ত, আমরা আমরা সর্বদা এর মান জানি F[N](এবং এমএসবি বিট উপস্থাপনায় শূন্য হয়) পর্যবেক্ষণ করে পুনরাবৃত্ত অনুসন্ধানের উপর উন্নতি করতে পারি । এটি আমাদের অভ্যন্তরীণ পণ্য থেকে কোন শাখায় পুনরাবৃত্তি করে তা সুনির্দিষ্টভাবে অনুমান করতে দেয়। যদিও এটি আসলে আমাদের পুরো অনুসন্ধানটিকে একটি পুনরাবৃত্ত লুপে রূপান্তর করতে দেয়, যা শাখার পূর্বাভাসটি বেশ খানিকটা স্ক্রুতে ঘটেছিল, তাই আমরা শীর্ষ স্তরের মূল আকারে রাখি। আমরা এখনও কিছু সময় সাশ্রয় করি, প্রাথমিকভাবে আমরা যে শাখাগুলি করছি তার পরিমাণ হ্রাস করে।

কিছু পরিষ্কার করার জন্য, কোডটি এখন স্বাক্ষরবিহীন পূর্ণসংখ্যা ব্যবহার করছে এবং সেগুলি 64৪-বিটে স্থির করছে (কেবলমাত্র কেউ যদি 32-বিট আর্কিটেকচারে এটি চালাতে চান) wants

সামগ্রিক স্পিডআপ x3 এবং x4 এর একটি ফ্যাক্টরের মধ্যে is এন = 22 টি 10 ​​মিনিটের অধীনে চলতে আট কোরেরও বেশি প্রয়োজন, তবে একটি 64৪-কোর মেশিনে এটি এখন প্রায় চার মিনিটের মধ্যে নেমে গেছে ( numThreadsসেই অনুযায়ী ধাক্কা দিয়ে) with যদিও আমি আলাদা আলাদা অ্যালগরিদম ছাড়া উন্নতির আরও অনেক জায়গা আছে বলে মনে করি না।

এন = 22:

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

অনুসন্ধানের জায়গায় আরও সম্ভাব্য হ্রাস ব্যবহার করে আবার আপডেট হয়েছে। আমার কোয়াডকোয়ার মেশিনে এন = 22 এর জন্য প্রায় 9:49 মিনিটের মধ্যে চলে।

চূড়ান্ত আপডেট (আমার মনে হয়)। আমার পছন্দসই এফ এর জন্য আরও সমতুল্য ক্লাস, এন = 22 এর জন্য রানটাইম কেটে 3:19 মিনিট 57 সেকেন্ডে (সম্পাদনা করুন: আমি দুর্ঘটনাক্রমে কেবলমাত্র একটি থ্রেড সহ এটি চালিয়েছি) আমার মেশিনে।

এই পরিবর্তনটি এই সত্যটি ব্যবহার করে যে এক জোড়া ভেক্টর একই লিডিং জিরো তৈরি করে যদি একজনকে অন্যকে ঘোরানোর মাধ্যমে অন্যটিতে রূপান্তর করা যায়। দুর্ভাগ্যক্রমে, মোটামুটি সমালোচিত নিম্ন-স্তরের অপ্টিমাইজেশনের জন্য বিট উপস্থাপনায় এফের শীর্ষ বিটটি সর্বদা একই থাকে এবং এই সমতা ব্যবহার করার সময় অনুসন্ধানের স্থানটি বেশ খানিকটা কমে যায় এবং রানটাইমকে আলাদা স্টেট স্পেস ব্যবহার করে প্রায় এক চতুর্থাংশ কমে যায় reduced F এ হ্রাস, ওপেনহেড এটি অফসেটের চেয়ে কম স্তরের অপ্টিমাইজেশনকে বাদ দেওয়া থেকে। তবে দেখা যাচ্ছে যে এফ যে একে অপরের বিপরীতমুখী সেগুলিও সমান considering এটি সমতা শ্রেণির গণনার জটিলতায় কিছুটা যোগ করার পরে, এটি আমাকে উপরোক্ত নিম্ন-স্তরের অপ্টিমাইজেশন ধরে রাখতেও অনুমতি দেয়, যার ফলে প্রায় 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)

এন = 22 এর সাথে ফলাফলটি 12410090985684467712 যা .4৩.৪২ বিট নেয় এবং এইভাবে স্বাক্ষরবিহীন 64৪-বিটে ফিট করে।
স্টিফান

2
আপনি অবশ্যই খুব চিত্তাকর্ষকভাবে বারটি উত্থাপন করেছেন।

1
কাউকে নিম্রড ব্যবহার করে দেখে ভাল লাগছে। :)
সিজেফুরে

@ স্টেফান হতে পারে আপনার কোডিং উইজার্ড্রি এন = 22 এর জন্য 10 মিনিটের নীচে এই পদ্ধতিটি পেতে পারে?

আমি এন = 22 চেষ্টা করেছিলাম যা কয়েক ঘন্টা পরে শেষ হয়ে যায়। তবে এটি আমাকে দেয় [-6036653088025083904, 2087229562810269696, 351473149499408384, 59178309967151104, 9975110458933248, 1682628717576192, 284866824372224, 48558946385920, 8416739196928, 1518499004416, 301448822784, 71620493312, 22100246528, 8676573184, 3897278464, 1860960256, 911646720, 451520512, 224785920, 112198656, 56062720, 28031360, 14015680] যা একটি ওভারফ্লো ত্রুটি বলে মনে হচ্ছে। আমি কোনও নিম্রড জানি কিন্তু এটি সমাধান করার জন্য কি স্বাক্ষরবিহীন ইনট ব্যবহার করা সম্ভব?

11

জাভা ( n=22?)

আমি মনে করি বেশিরভাগ উত্তর যা এর সাথে n=16একই রকমের পদ্ধতির ব্যবহারের চেয়ে ভাল করে , যদিও তারা শোষণ করে এমন প্রতিসাম্যগুলির মধ্যে এবং তারা যেভাবে টাস্কের মধ্যে টাস্ককে ভাগ করে দেয় তাতে আলাদা।

প্রশ্নের মধ্যে সংজ্ঞায়িত ভেক্টরগুলিকে বিট স্ট্রিংগুলির সাথে প্রতিস্থাপিত করা যেতে পারে এবং ওভারল্যাপিং উইন্ডোটি এক্সওরিংয়ের সাথে অভ্যন্তরীণ পণ্যটি সঠিকভাবে n/2বিট সেট রয়েছে তা পরীক্ষা করে (এবং n/2বিটগুলি সাফ করা হয়েছে)। আছে n! / ((n/2)!)(সেন্ট্রাল দ্বিপদ সহগ) এর স্ট্রিং nসঙ্গে বিট n/2সেট বিট (যা আমি ফোন সুষম স্ট্রিং), তাই কোনো দেওয়া Fযে অনেক জানালার হয় Sযা শূন্য ভেতরের পণ্য দেব। তদুপরি, Sএক সাথে স্লাইডিং এবং যা আমরা এখনও একটি ইনকামিং বিট খুঁজে পেতে পারি যা যা শূন্য অভ্যন্তরীণ পণ্যটি দেয় তার গ্রাফের একটি প্রান্ত অনুসন্ধান করার সাথে মিলিত হয় যা যা নোডগুলি উইন্ডোজ এবং যার প্রান্তগুলি নোডের uসাথে নোডের সাথে যুক্ত করে vযার প্রথম n-1বিটগুলি শেষ হয়n-1এর বিট u

উদাহরণস্বরূপ, n=6এবং F=001001আমরা এই গ্রাফটি পাই:

এফ = 001001 এর জন্য গ্রাফ

এবং F=001011আমরা এই গ্রাফ পেতে:

এফ = 001011 এর জন্য গ্রাফ

তারপর আমরা প্রতিটি জন্য গণনা করা প্রয়োজন iথেকে 0করা nকিভাবে দৈর্ঘ্য অনেক পাথ i, আছে যে জন্য গ্রাফ উপর summing F। আমি মনে করি আমাদের মধ্যে বেশিরভাগ গভীরতা-প্রথম অনুসন্ধান ব্যবহার করছে।

উল্লেখ্য যে গ্রাফগুলি অপ্রয়োজনীয়: এটি প্রমাণ করা সহজ যে প্রতিটি নোডে সর্বাধিক 1 এর স্নাতক এবং সর্বাধিক একের ডিগ্রি থাকে। এর অর্থ হ'ল সম্ভব একমাত্র কাঠামো হ'ল সহজ চেইন এবং সহজ লুপ। এটি ডিএফএসকে কিছুটা সহজ করে।

আমি বেশ কয়েকটি প্রতিসাম্য কাজে লাগিয়েছি: ভারসাম্যযুক্ত স্ট্রিংগুলি বিট ইনভার্সের অধীনে ( ~ALGOL পরিবার থেকে বহু ভাষায় অপারেশন) এবং বিট রোটেশনের অধীনে বন্ধ রয়েছে, তাই আমরা Fএই অপারেশনগুলির সাথে সম্পর্কিত যেগুলির মানগুলি একত্রিত করতে পারি এবং কেবল ডিএফএস করি একদা.

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 কোর 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 মিনিটেরও কম সময়ে কার্যকর হবে ।


7:17! খুব সুন্দর. আপনার পদ্ধতিটি আরও কিছুটা ব্যাখ্যা করতে আপনি কি আপত্তি করবেন?

6

সি

এটি মূলত প্রশ্নের মধ্যে থাকা অ্যালগোরিদমের কিছুটা অনুকূলিতকরণ বাস্তবায়ন implementation এটি 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 ব্যবহার করে দেখুন

There were a couple of unused variables forgotten from an earlier iteration, but I removed them so at least a couple of warnings should have disappeared. I don't have GCC available at the moment (only Clang), and Clang doesn't give me any warnings at the moment (after removing the unused variables). And as Clang usually is more strict when it comes to warnings I must say I'm a bit surprised that you got any warnings at all.
Fors

It complains about Fors.c:13:17: warning: suggest parentheses around ‘-’ in operand of ‘&’ [-Wparentheses] (twice) and also warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘uint64_t’ [-Wformat=] . In fact clang complains about the printf statement too for me,

With the latest changes GCC shouldn't throw any warning messages.
Fors

It still complains about Fors.c:13:49: warning: suggest parentheses around arithmetic in operand of ‘^’ [-Wparentheses] But in worse news... it takes longer than 10 minutes on my machine.

5

Java, n=16

For any given value of F there are \binom{n}{n/2} vectors which have a zero inner product with it. So we can build a graph whose vertices are those matching vectors and whose edges correspond to the shifting of S, and then we just need to count paths of length up to n in the graph.

I haven't tried microoptimising this by replacing conditionals with bitwise operations, but each double-increment of n increases running time about 16-fold, so that's not going to make enough of a difference unless I'm pretty close to the threshold. On my machine, I'm not.

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("]");
    }
}

On my 2.5GHz Core 2 I get

$ 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

Piggybacking since I don't want to implement my own solution right now. Each vertex has at most one successor, so you don't really need the array. To iterate efficiently over combinations of f and starting vertices, iterate over all f_xor_g with exactly n/2 set bits. For each of these, iterate over all f and take g = f ^ f_xor_g.
David Eisenstat

@David, I know, and my version 7 does n=18 in one minute on my Atom netbook, but I can't post it until I get back from holiday.
Peter Taylor

4

RPython, N=22 ~3:23

Multi-threaded, using a stackless recursive descent. The program accepts two command line arguments: N, and the number of worker threads.

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

To Compile

Make a local clone of the PyPy repository using mercurial, git, or whatever you prefer. Type the following incantation (assuming the above script is named convolution-high.py):

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

where %PYPY_REPO% represents an environment variable pointing to the repository you just cloned. Compilation takes about one minute.


Sample Timings

N=16, 4 threads:

$ 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

N=18, 4 threads:

$ 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

N=20, 4 threads:

$ 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

N=22, 4 threads:

$ 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

9:26. Welcome to the 22 crew :)

I am not sure why but your new version is no faster for me. Still about 9:30 when I do time ./primo-c 22 8 .

@Lembik that would make sense if division were about as fast on average as 3 right shifts (3=Sum{(n+1)/(2^n)},n=1..infty). For certian architectures, I suppose that might be the case, but on mine division is noticably slower. Thanks for taking the time to test it :)
primo

3

Python 3.3, N = 20, 3.5min

Disclaimer: my intention is NOT to post this as my own answer, since the algorithm I'm using is only a shameless port from primo's RPython solution. My purpose here is only to show what you can do in Python if you combine the magic of Numpy and Numba modules.

Numba explained in short:

Numba is an just-in-time specializing compiler which compiles annotated Python and NumPy code to LLVM (through decorators). http://numba.pydata.org/

Update 1: I noticed after tossing the numbers around that we can simply skip some of the numbers completely. So now maxf becomes (1 << n) // 2 and maxs becomes maxf2**. This will speed up the process quite a bit. n = 16 now takes only ~48s (down from 4,5min). I also have another idea which I'm going to try and see if I can make it go a little faster.

Update 2: Changed algorithm (primo's solution). While my port does not yet support multithreading it is pretty trivial to add. It is even possible to release CPython GIL using Numba and ctypes. This solution, however, runs very fast on single core too!

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)

And finally:

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))

This runs on my machine in 212688ms or ~3.5min.


Thanks. Now how about n = 18 ? :)

It has been almost 20min since I started the program using n = 18. I think it is safe to say that Python can't solve this even with Numba on time using this particular algorithm.
Anna Jokela

I am optimistic that a better algorithm exists.

I tried pip install numba but it says it can't find llvmpy. I tried sudo pip install llvmpy but it says it can't find versioneer. I tried sudo pip install versioneer but it says I already have it.

Although I haven't got numba to work yet (I think I will have to install anaconda in the end) I am impressed by this. The question is, can you get it to solve N=22 using a similar method to the nimrod one?

2

C++ N=16

I'm testing on a EEEPC with an atom.. my time don't make a lot of sense. :D
The atom solve n=14 in 34 seconds. And n=16 in 20 minutes. I want to test n = 16 on OP pc. I'm optimistic.

The ideas is that every time we find a solution for a given F we have found 2^i solution because we can change the lower part of S leading to the same result.

#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;
}

to compile:

gcc 26459.cpp -std=c++11 -O3 -march=native -fstrict-aliasing -ftree-vectorize -Wall -pedantic -o 26459


1
This is great. I have some half-baked ideas in fact for how to solve it for larger n. Would you like to hear them or could that spoil the competition?

2

JAVASCRIPT n:12

In my computer it took 231.242 seconds. In the Demo I'm using webworkers to prevent freezing the browser. This sure can be further improved with parallel workers. I know JS don't stand a chance in this challenge but I did it for fun!

Click to run the online Demo

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;

What about one of those new(ish) fast javascript engines? Could those be used?

You mean something like dart?
rafaelcastrocouto

1
Actually I am wrong. You might as well just try both firefox and chromium. Unless you want to write it in asm.js of course :)

1
challenge accepted ... gonna do it!
rafaelcastrocouto

1
Tried this and took my computer 5.4 seconds to do 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

Fortran: n=12

I just made a quick'n'dirty version in Fortran, no optimizations except OpenMP. It should squeeze in at just below 10 minutes for n=12 on the OPs machine, it takes 10:39 on my machine which is sligthly slower.

64-bit integers have a negative performance impact indeed; guess I would have to rethink the whole algorithm for this to be much faster. Don't know if I'm going to bother, I think I'll rather spend some time thinking up a good challenge that's more to my own tastes. If anyone else wants to take this and run with it, go ahead :)

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

Lua: n = 16

Disclaimer: my intention is NOT to post this as my own answer, since the algorithm I'm using is shamelessly stolen from Anna Jokela's clever answer. which was shamelessly stolen from ilmale's clever answer.

Besides, it's not even valid - it has inaccuracies caused by floating point numbers (it would be better if Lua would support 64-bit integers). However, I'm still uploading it, just to show how fast this solution is. It's a dynamic programming language, and yet I can calculate n = 16 in reasonable time (1 minute on 800MHz CPU).

Run with LuaJIT, standard interpreter is too slow.

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

Thank you. I think recent lua versions use long long int which should be 64 bit on a 64 bit system. See "lua_integer" at lua.org/work/doc/manual.html .

@Lembik: Interesting. Either way, it's standard Lua (which already supports long long instead of double with a compilation setting), not LuaJIT.
Konrad Borowski

I think I was just wrong in any case wrt luajit. One would need 5.3 which doesn't exist. The best advice lua people could give was "try 5.3-workx".
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.