পাইথন সত্যিই কত ধীর (দ্বিতীয় খণ্ড)?


52

এই পর্যন্ত অনুসরণ করা হয় কিভাবে ধীর পাইথন আসলেই কি হয়েছে? (অথবা কত দ্রুত আপনার ভাষা রয়েছে?)

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

আরও অসুবিধা করতে আমি এবার পাইপি ব্যবহার করছি। পাইপি ২.২.১ ব্যবহার করে আমার জন্য বর্তমান সময়টি 1 মিনিট 7 সেকেন্ড

বিধি

  1. আমি চালাতে পারি এমন কোড জমা দেওয়ার প্রথম ব্যক্তিটি সঠিক এবং আমার মেশিনে এক্স 100 গুণ দ্রুত গতিতে 50 পয়েন্টের অনুদান দেওয়া হবে।
  2. আমি এক সপ্তাহ পরে দ্রুততম কোডটিতে জয়টি দেব will
import itertools 
import operator 
import random

n = 8 
m  = 8 
iters = 1000  

# creates an array of 0s with length m
# [0, 0, 0, 0, 0, 0, 0, 0]
leadingzerocounts = [0]*m

# itertools.product creates an array of all possible combinations of the 
# args passed to it.
#
# Ex:
#   itertools.product("ABCD", "xy") --> Ax Ay Bx By Cx Cy Dx Dy
#   itertools.product("AB", repeat=5) --> [
#    ('A', 'A', 'A', 'A', 'A'),
#    ('A', 'A', 'A', 'A', 'B'),
#    ('A', 'A', 'A', 'B', 'A'),
#    ('A', 'A', 'A', 'B', 'B'),
#    etc.
#   ]
for S in itertools.product([-1,1], repeat = n+m-1):
    for i in xrange(iters):
        F = [random.choice([-1,0,0,1]) for j in xrange(n)]

        # if the array is made up of only zeros keep recreating it until
        # there is at least one nonzero value.
        while not any(F):
            F = [random.choice([-1,0,0,1]) for j in xrange(n)]

        j = 0
        while (j < m and sum(map(operator.mul, F, S[j:j+n])) == 0):
            leadingzerocounts[j] +=1
            j += 1
print leadingzerocounts

আউটপুট অনুরূপ হওয়া উচিত

[6335185, 2526840, 1041967, 439735, 193391, 87083, 40635, 19694]

আপনাকে অবশ্যই আপনার কোডটিতে একটি এলোমেলো বীজ ব্যবহার করতে হবে এবং উপরের কাছাকাছি উত্তর দেওয়ার পক্ষে যথেষ্ট যে কোনও র্যান্ডম নম্বর জেনারেটর গ্রহণ করা হবে will

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

কোড ব্যাখ্যা

এই কোডটি দৈর্ঘ্যের এন + মি -1 এর সমস্ত অ্যারে এস-এর পুনরাবৃত্তি করে যা -1 এবং 1 এস পর্যন্ত তৈরি। প্রতিটি অ্যারে এস এর জন্য 1000-অ-শূন্য এলোমেলো অ্যারে F এর দৈর্ঘ্যের এন -1,0 বা 1 দিয়ে 1/4, 1/2, / 14 এর প্রতিটি মান গ্রহণের সম্ভাবনা সহ নমুনা করা হয়। এরপরে এফ এবং দৈর্ঘ্যের এন এর প্রতিটি উইন্ডোর মধ্যে অভ্যন্তরীণ পণ্যগুলি গণনা করে যতক্ষণ না এটি একটি শূন্য-অভ্যন্তরীণ পণ্য খুঁজে পায়। এটি leadingzerocountsপ্রতিটি অবস্থানে 1 যোগ করে এটি একটি শূন্য অভ্যন্তরীণ পণ্য খুঁজে পায়।

অবস্থা

  • পার্ল । @ টোবাইঙ্ক দ্বারা ২.7 বার স্লোডাউন। (সিপাইথন নয় পাইপির তুলনায়।)

  • জে । 39 বার স্পিডআপ @ ইলেভেক্স দ্বারা

  • । @ গতিবেগে 59 বার গতি বাড়ান।
  • জুলিয়া । @ এক-মিনিট দ্বারা আরম্ভের সময়টি অন্তর্ভুক্ত না করে 197 বার দ্রুত faster প্রারম্ভকালীন সময় সহ 8.5 গুণ গতি বাড়ায় (এটি 8 এর চেয়ে 4 প্রসেসর ব্যবহার করে দ্রুত)।
  • ফোরট্রান । @ আধা-বহির্মুখী দ্বারা 438 বার গতি বাড়ান।
  • Rpython । 258 বার @ প্রিমো দ্বারা গতি বাড়ায়।
  • সি ++ । 508 বার @ ইলমাইল দ্বারা গতি বাড়ান।

(আমি নতুন উন্নতিগুলির সময়সীমা বন্ধ করে দিয়েছিলাম কারণ এগুলি খুব দ্রুত এবং এটির সংস্থানগুলি খুব কম ছিল))


এটি চিহ্নিত করা হয়েছিল যে এক সেকেন্ডের নীচের সময়গুলি অবিশ্বাস্য এবং কিছু ভাষার স্টার্ট-আপ ব্যয়ও হয়। যুক্তিটি হল যে আপনি যদি অন্তর্ভুক্ত করতে চান তবে আপনার সি / সি ++ ইত্যাদি সংকলনের সময়ও অন্তর্ভুক্ত করা উচিত Here এখানে পুনরাবৃত্তির সংখ্যা সহ দ্রুততম কোডের সময় 100,000 হয়ে গেছে।

  • জুলিয়া । এক সেকেন্ড-মিনিটে @ 42 সেকেন্ড
  • সি ++ । 14 সেকেন্ড @ গুয়েসার্টন দ্বারা।
  • ফোরট্রান । 14 টি @ অর্ধ-বহিরাগত দ্বারা।
  • সি ++ । 12s @ ইলমেলে দ্বারা
  • Rpython । 18 এর দশকে @ প্রিমো।
  • সি ++ । @ স্টেফান দ্বারা 5s।

বিজয়ী .. স্টেফান!

ফলো-আপ চ্যালেঞ্জ পোস্ট করা হয়েছে। কিভাবে উচ্চ আপনি যেতে পারেন? (একটি কোডিং + অ্যালগোরিদম চ্যালেঞ্জ) । এই এক কঠিন।


3
কোডটি কী অর্জন করতে অনুমান করা হয়েছে তার ব্যাখ্যাটি দুর্দান্ত হবে, তাই আমরা এটিকে পুনরায় লিখতে পারি এবং এটি কেবল পোর্ট করতে পারি না
আইনাসিও

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

5
@ আইনাসিও এটি একটি দুর্দান্ত ধারণা। আমি নিয়মগুলি পরিবর্তন করেছি যা আমি আশা করি কেউ আপত্তি করবে না।

1
@ ল্যাম্বিক আমি আমার ফোর্টরান সংস্করণটি উন্নত করেছি, এটি আমার মেশিনে আবার 2x দ্রুত তৈরি করেছে। আপনি আবার সময় করতে পারেন? :)
আধা-বহিরাগত

1
@ আধা-বহির্মুখী সমাপ্ত।

উত্তর:


12

সি ++ বিট যাদু

Ms 16 মিলিয়নস মাল্টিথ্রেড, 56 মিমি সিঙ্গলথ্রেড। 000 4000 গতি।

(স্পিডআপ আমার আই -2-২৮২০ কিউএম-তে মাল্টিথ্রেড কোড এবং প্রশ্নে উল্লিখিত 1 মিনিট 9 সেকেন্ডের উপর ভিত্তি করে। ওপি-র সিস্টেমটিতে আমার সিপিইউর চেয়ে আরও বেশি একক থ্রেডেড পারফরম্যান্স রয়েছে তবে ভাল মাল্টি থ্রেড পারফরম্যান্স আমি আশা করি এই সংখ্যাটি সঠিক হবে)

থ্রেডের স্প্যানিংয়ের কারণে মাল্টিথ্রেডেড অংশটি বেশ অযোগ্য। আমি আমার কাস্টম জব লাইব্রেরিটি উন্নত করে আরও ভাল করতে পারলাম তবে ইউনিক্স সিস্টেমের অধীনে বাগগুলি রয়েছে .. থ্রেডিং ছাড়াই একটি ব্যাখ্যা এবং প্রায় অভিন্ন কোডের জন্য https://codegolf.stackexchange.com/a/26485/20965 দেখুন

সম্পাদন করা

আমি প্রতিটি থ্রেডের নিজস্ব আরএনজি দিয়েছি এবং বিট দৈর্ঘ্যটি কেটে 32 করে ফেলেছি যা রানটাইমকে কয়েক এমএস দ্বারা হ্রাস করেছে।

#include <iostream>
#include <bitset>
#include <random>
#include <chrono>
#include <stdint.h>
#include <cassert>
#include <array>
#include <tuple>
#include <memory>
#include <thread>
#include <future>
#include <string.h>


#ifdef _MSC_VER
uint32_t popcnt( uint32_t x ){ return _mm_popcnt_u32(x); }
#else
uint32_t popcnt( uint32_t x ){ return __builtin_popcount(x); }
#endif



void convolve()
{
    static const unsigned threadCount = 32;
    static const unsigned n = 8;
    static const unsigned m = 8;
    static const unsigned totalIters = 1000;
    static_assert( n <= 16, "packing of F fails when n > 16.");
    static uint32_t fmask = (1 << n) -1; fmask |= fmask << 16;

    std::array< uint32_t, m * threadCount > out;
    std::vector< std::future<void> > threads;

    for( int threadId = 0; threadId < threadCount; threadId++)
    {
        threads.emplace_back( std::async( [&, threadId]
        {
            std::random_device rd;
            std::knuth_b gen(rd());
            uint32_t nextRandomNumber = gen();

            const unsigned iters = totalIters / threadCount;

            std::array< uint32_t, m > leadingZeros;
            for( auto& x : leadingZeros )
                x = 0;

            for( unsigned i = 0; i < iters; i++ )
            {
                // generate random bit mess
                uint32_t F;
                do {
                    // this funky looking construction shortens the dependancy chain of F
                    F = nextRandomNumber & fmask;
                    nextRandomNumber = gen();
                } while ( 0 == ((F % (1 << n)) ^ (F >> 16 )) );

                // Assume F is an array with interleaved elements such that F[0] || F[16] is one element
                // here MSB(F) & ~LSB(F) returns 1 for all elements that are positive
                // and  ~MSB(F) & LSB(F) returns 1 for all elements that are negative
                // this results in the distribution ( -1, 0, 0, 1 )
                // to ease calculations we generate r = LSB(F) and l = MSB(F)

                uint32_t r = F % ( 1 << n );
                // modulo is required because the behaviour of the leftmost bit is implementation defined
                uint32_t l = ( F >> 16 ) % ( 1 << n );

                uint32_t posBits = l & ~r;
                uint32_t negBits = ~l & r;
                assert( (posBits & negBits) == 0 );

                uint32_t mask = posBits | negBits;
                uint32_t totalBits = popcnt( mask );
                // if the amount of -1 and +1's is uneven, sum(S*F) cannot possibly evaluate to 0
                if ( totalBits & 1 )
                    continue;

                uint32_t adjF = posBits & ~negBits;
                uint32_t desiredBits = totalBits / 2;

                uint32_t S = (1 << (n + m -1));
                // generate all possible N+1 bit strings
                // 1 = +1
                // 0 = -1
                while ( S-- )
                {
                    for( int shift = 0; shift < m; shift++ )
                    {
                        uint32_t s = (S >> shift) % ( 1 << n );
                        auto firstBits = (s & mask) ^ adjF;

                        if ( desiredBits == popcnt( firstBits ) )
                        {
                            leadingZeros[shift] = leadingZeros[shift] + 1;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            memcpy( out.data() + (threadId * m), leadingZeros.data(), sizeof( leadingZeros[0] ) * m );
        } ));

    };

    std::array< uint32_t, m > leadingZeros;
    for( auto& x : leadingZeros )
        x = 0;

    for( auto& thread : threads )
    {
        thread.wait();
    }

    for( int i = 0; i < (threadCount * m); i++ )
    {
        leadingZeros[i % m] += out[i];
    }


    for( auto x : leadingZeros )
        std::cout << x << ", ";

    std::cout << std::endl;
}

int main()
{
    typedef std::chrono::high_resolution_clock clock;
    int rounds = 100;

    // do some rounds to get the cpu up to speed..
    for( int i = 0; i < rounds / 10; i++ )
    {
        convolve();
    }


    auto start = clock::now();

    for( int i = 0; i < rounds; i++ )
        convolve();

    auto end = clock::now();
    double seconds = std::chrono::duration_cast< std::chrono::microseconds >( end - start ).count() / 1000000.0;

    std::cout << seconds/rounds*1000 << " msec/round" << std::endl;

    return 0;
}

নমুনা আউটপুট:

   6317312, 2515072, 1034368, 434048, 190144, 85200, 39804, 19168,
   6226944, 2481408, 1031168, 438080, 192896, 86816, 40484, 19490,
   6321152, 2524672, 1045376, 442880, 195680, 88464, 41656, 20212,
   6330624, 2517504, 1031104, 430208, 187696, 83976, 38976, 18708,
   6304768, 2510336, 1030720, 433056, 190880, 86824, 40940, 19840,
   6272512, 2494720, 1028160, 432352, 189168, 84752, 39540, 19052,
   6233600, 2507520, 1046912, 447008, 198224, 89984, 42092, 20292,

আউটপুটটি সঠিক নয় বলে আমি মনে করি, সম্ভবত কোনও বাগ আছে? প্রশ্নে যা আছে তার সাথে তুলনা করুন। বিশেষত শেষ কলামটি 19180 এর কাছাকাছি একটি নম্বর হওয়া উচিত user

@ ল্যাম্বিক আপনি কী বলতে চাইছেন তা আমি দেখতে পাচ্ছি। আমি মনে করি যে এলোমেলো আউটপুট এলোমেলোভাবে নয় যা মাঝে মাঝে ফানকি আউটপুট তৈরি করে। সি ++ 11 এলোমেলো জেনারেটরের সাথে এটি দুর্দান্ত কাজ করে। আমি আজকে পরে কোডটি ঠিক করব।
স্টিফান

আমি স্টেফান.সি.পি: 104: 101: ত্রুটি: 'মেমকিপি' ঘোষিত হয়নি এই সুযোগে মেমকি (আউটডেটা () + (থ্রেডআইডি * এম), লিডিং জেরোস.ডাটা (), সাইজফ (লিডিং জেরোস [0]) * মি );

আমি মনে করি আমার স্ট্রিং। H অন্তর্ভুক্ত করা দরকার। এটা আবার চেষ্টা কর.
স্টিফান

আপনি এটি g ++ -O3 -std = c ++ 0x -pthread -Wl দিয়ে সংকলন করুন - কোনও প্রয়োজন অনুসারে Stefan.cpp -o Stefan

16

সি ++ x150 x450 x530

অ্যারের পরিবর্তে আমি বিট (এবং গা dark় যাদু) ব্যবহার করি।
দ্রুত এলোমেলো কাজের জন্য @ace ধন্যবাদ ace

এটি কীভাবে কাজ করে: পূর্ণসংখ্যার প্রথম 15 তম বিটগুলি sঅ্যারের প্রতিনিধিত্ব করে S[15]; শূন্যরা -1 প্রতিনিধিত্ব করে, +1 প্রতিনিধিত্ব করে। অ্যারে Fএকইভাবে নির্মিত হয়। তবে প্রতিটি চিহ্নের জন্য দুটি বিট সহ।

  • 00 প্রতিনিধিত্ব -1
  • 01 এবং 10 0 প্রতিনিধিত্ব করে
  • 11 উপস্থাপন 1

কারণ Sএবং Fএকটি ভিন্ন প্রতিনিধিত্ব আমি বইয়ের পাতার মাঝে মাঝে আছে Sনিজেই সঙ্গে তুলনীয় হতে F

  • 0 (-1) হয়ে ওঠে 00 (-১ এর প্রতিনিধিত্ব করে F)
  • 1 (+1) 11 (+1 এর প্রতিনিধিত্ব করে F) হয়ে গেছে

এখন আমরা কেবল অভ্যন্তরীণ পণ্য গণনা করতে কার্নোট ব্যবহার করতে পারি। মনে রাখবেন যে একটি ভেরিয়েবল কেবল 00 বা 11 এর মান ধরে নিতে পারে

0 00 = 11 (-1 * -1 = +1)
0। 01 = 10 (-1 * 0 = 0)
0। 10 = 01 (-1 * 0 = 0)
0। 11 = 00 (-1 * +1 = -1)
1। 00 = 00 (+1 * -1 = -1)
1। 10 = 10 (+1 * 0 = 0)
1। 01 = 01 (+1 * 0 = 0)
1। 11 = 11 (+1 * +1 = +1)

আমার কাছে একরকম নয়ন বলে মনে হচ্ছে। :)

সমষ্টিগুলি হ'ল শিফট এবং মাস্কের খেলা, আসলে কিছুই জটিল।

#include <array>
#include <ctime>

// From standford bithacks
// http://graphics.stanford.edu/~seander/bithacks.html
inline int32_t interleaveBit(int32_t x)
{
   static const uint32_t B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF };
   x = (x | ( x << 8)) & B[3];
   x = (x | ( x << 4)) & B[2];
   x = (x | ( x << 2)) & B[1];
   x = (x | ( x << 1)) & B[0];
   return x | (x << 1);
}

inline int32_t sumOnes(int32_t v)
{
   static int b[] = { 1, 0, 0, 1};
   int s = 0;
   for( int i = 0; i < 8; ++i)
   {
      const int a = 3&(v>>(i*2));
      s += b[a];
   }
   return s;
}

inline int32_t sumArray(int32_t v)
{
   static int b[] = { -1, 0, 0, 1};
   int s = 0;
   for( int i = 0; i < 8; ++i)
   {
      const int a = 3&(v>>(i*2));
      s += b[a];
   }
   return s;
}

uint32_t x, y = 24252, z=57768, w=1564; //PRNG seeds

int32_t myRand()
{
   uint32_t t;
   t = x ^ (x<<1);
   x = y;
   y = z;
   z = w;
   w = w ^ ( w >> 19) ^ t ^ (t >> 8);
   return w;
}

int main()
{
   std::array<int, 8> leadingZero{0};
   x = static_cast<int32_t>(time(nullptr)); // seed PRNG
   const int maxS = 1 << 15;
   for(int s = 0; s < maxS; ++s)
   {
      const int32_t x = interleaveBit(s);
      for(int i = 0; i < 1000; ++i)
      {
         int32_t random;
         do
         {
            random = 0xFFFF & myRand();
         }while(sumOnes(random) == 0);
         int j = 7;
         while( j >= 0 )
         {
            const int32_t h = (x >> (j*2));
            const int32_t l = 0xFFFF & (~(random ^ h)); // inner product
            if(sumArray(l) == 0)
            {
               leadingZero[j]++;
            } else
            {
               break;
            }
            j--;
         }

      }
   }
   for(int i = 7; i >= 0; --i)
   {
      printf("%d ", leadingZero[i]);
   }
   printf("\n");
   return 0;
}

এখানে একটি নমুনা আউটপুট:

6332350 2525218 1041716 438741 192917 87159 41023 19908 

real 0m0.372s
user 0m0.371s
sys  0m0.001s

প্রোগ্রামটি সংকলিত হয়েছে:

gcc -std=c++11 -O3 -msse4.2 -Wall -lstdc++ 26371.cpp -o fastPy

ফেডোরা ২০-এ জিসিসি ৪.৮.২ সহ সিপিইউ একটি আই 8 8कोर।

সম্ভবত আমি কিছু এমএস টুইটের সংকলক পরামিতি অর্জন করতে পারি।

যদিও এটি আমার মেশিনে ওপি সমাধানের সময়:

time pypy 26371.py
[6330609, 2523914, 1040885, 439303, 192708, 86987, 40710, 19498]

real 0m53.061s
user 0m53.016s
sys  0m0.022s

সম্পাদনা:

কেবল ওপেনপ্যাম যুক্ত করুন এবং এর ক্রমটি পরিবর্তন করুন আমার কাছে একটি এক্স 3 লাভ রয়েছে, এটি ওপি কোডের বিপরীতে একটি x450 পারফরম্যান্স উন্নতি করতে পারে। : ডি এক্ষেত্রে leadingZeroঅ্যারে অবশ্যই পারমাণবিক হতে হবে। র্যান্ডম গ্লোবাল ... এলোমেলো, তারা আরও এলোমেলো হবে।

 #pragma omp parallel for
 for(int i = 0; i < 1000; ++i)
 {
    int32_t random;
    do
    {
       random = 0xFFFF & myRand();
    }while(sumOnes(random) == 0);
    for(int s = 0; s < maxS; ++s)
    {
       const int32_t x = interleaveBit(s);
       int j = 7;
       while( j >= 0 )
       {
          const int32_t h = (x >> (j*2));
          const int32_t l = 0xFFFF & (~(random ^ h)); // inner product
          if( sumArray(l) == 0 )
          {
             leadingZero[j]++;
          } else
          {
             break;
          }
          j--;
       }
    }
 }

-fopenmpসংকলক পতাকা যোগ করতে হবে


সম্পাদনা করুন: 2 ব্যবহারকারী 71404 এর পরামর্শক হিসাবে আমি SumOnes এবং SumArray ফাংশনগুলি পরিবর্তন করেছি এবং এখন এটি খুব দ্রুত।

real  0m0.101s
user  0m0.101s
sys   0m0.000s

ওপেনপ্যামটি ধীর গতির সাথে, পরমাণুগুলি অত্যধিক ওভারহেড যুক্ত করার কারণ।

real  0m0.253s
user  0m1.870s
sys   0m0.001s

অ্যাটমিক্স ছাড়া আরও দ্রুত, তবে আমি ভুল ফলাফল পেয়েছি।

2137992 1147218 619297 321243 155815 70946 32919 15579

real   0m0.048s
user   0m0.338s
sys    0m0.001s

SumArray বোঝার জন্য বিবেচনা করুন যে 16 বিটের প্রতিনিধিত্ব এবং 8 টি সংখ্যার অ্যারে।
00 এর কোনও 1 নেই এবং প্রতিনিধিত্ব করুন -1
01 এবং 10 এর একটি 1 আছে এবং 0
11 টি প্রতিনিধিত্ব করুন 2 টি রয়েছে এবং 1 টি উপস্থাপন করুন
যাতে অন্তর্নির্মিত বিটের সংখ্যা 1 তে সেট করা হয় [ http://en.wikedia.org/wiki/ হামিং_ ওয়েট] এবং প্রতিটি গোষ্ঠীর কাছে আমরা 1 টি সরান।

SumOnes কেবল কালো যাদু।

এখানে সর্বশেষতম ফ্ল্যাগ এবং কোড সংকলন করুন।

gcc -std = c ++ 11 -mfpmath = sse -O3 -flto -march = নেটিভ-ফুনরোল-লুপস-ওয়াল-এলএসডিডিসি ++

#include <cstdint>
#include <cstdio>
#include <ctime>

inline int32_t interleaveBit(int32_t x)
{
   static const uint32_t B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF };
   x = (x | ( x << 8)) & B[3];
   x = (x | ( x << 4)) & B[2];
   x = (x | ( x << 2)) & B[1];
   x = (x | ( x << 1)) & B[0];
   return x | (x << 1);
}

inline int32_t sumOnes(int32_t v)
{
   /* 0xAAAA == 0b1010 1010 1010 1010 */
   return !!(0xAAAA & (v ^ ~(v << 1)));
}

inline int32_t sumArray(int32_t v)
{
   return __builtin_popcount(v) - 8;
}

uint32_t x, y = 24252, z = 57768, w = 1564; //PRNG seeds

int32_t myRand()
{
   uint32_t t;
   t = x ^ (x << 1);
   x = y;
   y = z;
   z = w;
   w = w ^ ( w >> 19) ^ t ^ (t >> 8);
   return w;
}

int main()
{
   int leadingZero[8] = { 0 };
   x = static_cast<int32_t>(time(nullptr)); // seed PRNG
   const int maxS = 1 << 15;
   for( int i = 0; i < 1000; ++i )
   {
      int32_t random;
      do
      {
         random = 0xFFFF & myRand();
      } while(sumOnes(random) == 0 );
      for( int s = 0; s < maxS; ++s )
      {
         const int32_t x = interleaveBit(s);
         int j = 7;
         while( j >= 0 )
         {
            const int32_t h = (x >> (j * 2));
            const int32_t l = 0xFFFF & (~(random ^ h)); // inner product
            if( sumArray(l) == 0 )
            {
               leadingZero[j]++;
            } else
            {
               break;
            }
            j--;
         }
      }
   }
   printf("[%d, %d, %d, %d, %d, %d, %d, %d]\n",
      leadingZero[7], leadingZero[6],
      leadingZero[5], leadingZero[4],
      leadingZero[3], leadingZero[2],
      leadingZero[1], leadingZero[0]);
   return 0;
}

এখন আমি এটি পরীক্ষা করার জন্য অপেক্ষা করতে পারি না! দুঃখজনকভাবে এই কয়েক ঘন্টা জন্য হবে না।

1
নিম্নলিখিতটি একটি প্রস্তাবিত সম্পাদনায় ছিল, তবে আমি মনে করি এটি একটি মন্তব্য হিসাবে আরও ভাল ফিট করতে পারে। আপনি আপনার SumOnes প্রতিস্থাপন করতে পারেন, নিম্নলিখিত সাথে SumArray (ওপেনএমপি সংস্করণে আমাকে 2x গতি বাড়িয়ে দেবে বলে মনে হচ্ছে)। inline int32_t sumOnes(int32_t v) { /* 0xAAAA == 0b1010 1010 1010 1010 */ return !! (0xAAAA & (v ^ ~(v << 1))); } inline int32_t sumArray(int32_t v) { return __builtin_popcount(v) - 8; }এটি @ ব্যবহারকারী 71404
এসহোহংকং ইন্ডিপেন্ডেন্স

@ ইউজার 40০৪০৪: প্রোফাইলার বলেছেন যে এই দুটি কার্যক্রমে প্রোগ্রামটি তার সমস্ত সময় ব্যয় করেছিল, তবে গতকাল আমি সত্যিই ক্লান্ত হয়ে পড়েছিলাম যে এটি আরও ভাল কিছু মনে করে। আমি আজ সন্ধ্যায় চেষ্টা করব (ইউটিসি)। ধন্যবাদ।
ইলমলে

আপনি কি দ্বিতীয় কোড স্নিপেটকে সম্পূর্ণ অনুলিপি এবং পাস্তেবল কোড হিসাবে পরিবর্তন করতে আপত্তি করবেন? আপনার ওপেনএমপি কোডটি কাজ করার জন্য আমার প্রয়াসে আমি অবশ্যই কিছু ভুল করছি যাতে এটি অনেক সাহায্য করবে।

খুশী হলাম। আমি ভেবেছিলাম বিট অপারেশন দিয়ে এটি করা যেতে পারে।
গাই স্যারটন

10

জুলিয়া: 0.7 এস, 120x দ্রুত

ব্যবহারকারী 20768 হিসাবে দেখানো হয়েছে, জুলিয়াকে কোডের একটি সোজাসাপ্ট বন্দর পিপাইয়ের থেকে দ্বিগুণ দ্রুত। তবে আমরা এর থেকে অনেক বেশি ভাল করতে পারি।

function pleadingzerocounts(; n = 8,
                              m = 8,
                              iters = 1000)
  @parallel (+) for S = 1:2^(8+8-1)
    leading_counts = zeros(Int, m)
    F = Array(Int, n)
    for i = 1:iters
      flag = 0
      while flag == 0
        for i = 1:n
          v = (1-(rand(Int8)&3))%2
          @inbounds F[i] = v
          flag += v & 1
        end
      end
      for j = 1:m
        sum = 0
        for i = 1:n
          @inbounds sum += S & (1 << (j + i - 2)) > 0 ? F[i] : -F[i]
        end
        sum == 0 ?
          (leading_counts[j] += 1) :
          break
      end
    end
    leading_counts
  end
end

function main()
  # Warm up the JIT
  pleadingzerocounts()
  # Then go for real
  println(@time pleadingzerocounts())
end

আপনি এটি ব্যবহার করে চালাতে পারেন julia -p 8 -e 'require("golf.jl");main()'(8 টি প্রক্রিয়ার সংখ্যা, আপনি এটির সাথে খেলতে চাইতে পারেন)। সর্বশেষতম জুলিয়া প্রিরিলেজে পিপিপির জন্য এটি 0.7s বনাম 1 এম 22 সেকেন্ড নেয়।

আপনার কম্পিউটারে যদি আপনার পর্যাপ্ত পরিমাণে কোর থাকে এবং সম্ভবত কয়েকটি এডাব্লুএস উদাহরণ সজ্জিত করে থাকেন তবে আপনার আরও কয়েকটি শেভ করতে সক্ষম হবেন :)


আমি নিশ্চিত আপনি সময়কে ভুল মাপছেন। পাইপির সাথে পাইথনও জেআইটি-ভিত্তিক ভাষা, তবে ওপি তৈরির সময়গুলিতে জেআইটি সংকলনের সময় অন্তর্ভুক্ত করে। আপনি এটি বাদ দিচ্ছেন। আমি সর্বশেষ জুলিয়া গিট সংস্করণ ইনস্টল করেছি এবং আপনার কোডটি পরীক্ষা করেছি এবং আমার মেশিনে 8 টি প্রক্রিয়া সহ আপনার কমান্ডটি শেষ হতে 6.6 সেকেন্ড সময় নেয়, তবে এটি "অতিবাহিত সময় 0.588 .. সেকেন্ড" প্রিন্ট করে।
আধা-বহির্মুখী

পাইথন টাইমিংয়ের সাথে পাইপাই স্টার্টআপ এবং জেআইটি ওয়ার্মআপ অন্তর্ভুক্ত থাকে তবে এতে সেকেন্ড সময় লাগে - রানটাইমের এক মিনিটের ব্যবধানটি নগণ্য। আমি খুশী যদি ওপি পাইথনের সময় ঠিক করার পদ্ধতি পরিবর্তন করে (এটি কোনও তাত্পর্যপূর্ণ করবে না) তবে জুলিয়ার প্রারম্ভকালীন সময় যুক্তিসঙ্গত হবে না including
এক মিনিট-মিনিটের

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

সেক্ষেত্রে অনুকূল সমাধানটি হল সিরিয়াল অ্যালগরিদম ব্যবহার করা - এতে প্রায় 2s সময় লাগে। আমি কোডটি প্রকাশ করবো তবে এই প্রতিযোগিতাটি এখন কিছুটা বাড়াবাড়ি, যেহেতু প্রত্যেকে ইতিমধ্যে জানে যে সি ++ আরও দ্রুত সমস্ত কিছুর চেয়ে বুট করে।
এক মিনিট-মিনিটের

আমি সবেমাত্র আমার ফোর্টরান সমাধান পোস্ট করেছি, তাই আমি দেখতে পাচ্ছি না কেন আপনার দ্রুততম জুলিয়া পোস্ট করা উচিত নয় (যদি আপনার কাছে ইতিমধ্যে কোড থাকে)।
আধা-বহির্মুখী

5

সি, 1.210 এস

ওপির কোডটি আমার মেশিনে 1m45.729s চলছে।

সংকলন:

gcc -O3 -march=native -fwhole-program -fstrict-aliasing -ftree-vectorize -Wall ./test2.c -o ./test2

বিশেষ ধন্যবাদ: সংকলন পতাকা এবং অপ্টিমাইজেশনের জন্য ধারণার জন্য @ ডাইপ।

#include <stdio.h>
#include <time.h>

#define n (8)
#define m (8)
#define iters (1000)
int leadingzerocounts[m]; // declared as global so initialised to 0
unsigned int x,y=34353,z=57768,w=1564; //PRNG seeds

/* xorshift PRNG
 * Taken from https://en.wikipedia.org/wiki/Xorshift#Example_implementation
 * Used under CC-By-SA */
int myRand() {
    unsigned int t;
    t = x ^ (x << 11);
    x = y; y = z; z = w;
    return w = w ^ (w >> 19) ^ t ^ (t >> 8);
}

int dotproduct(int*F, int*S) {
    unsigned int i;
    int sum=0;
    for(i=0; i<n; i++) {
        sum+=F[i]*S[i];
    }
    return sum;
}

int main() {
    unsigned int i, j, tmp;
    x=(int)time(NULL); //seed PRNG

    int S[n+m-1];
    for(i=0; i<(1<<(n+m-1)); i++) {
        tmp=i;
        for(j=0; j<n+m-1; j++) {
            S[j]=(tmp&1)*(-2)+1;
            tmp>>=1;
        }
        for(j=0; j<iters; j++) {
            int F[n];
            unsigned int k, flag=0;
            do {
                for(k=0; k<n; k++) {
                    F[k]=(1-(myRand()&3))%2;
                    flag+=(F[k]&1);
                }
            } while(!flag);
            for(k=0; k<m&&!dotproduct(F, S+k); k++) {
                leadingzerocounts[k]++;
            }
        }
    }
    for(i=0; i<m; i++) printf("%d ", leadingzerocounts[i]);
    return 0;
}

নমুনা আউটপুট:

6334411 2527506 1042239 439328 192914 87005 40847 19728

1
সত্যই আকর্ষণীয়, আমি এই সমস্ত অপ্টিমাইজেশান পতাকা বাদ দেওয়ার সময় অনুরূপ পর্যবেক্ষণ করতে পারি। -march=native -fwhole-program -fstrict-aliasing -ftree-vectorizeবিটিডব্লিউ চেষ্টা করুন । আমি এমটি 19937 প্লাস এ সহ কয়েকটি সি ++ 11 ব্যবহার করে <4 s তে নামলাম uniform_int_distribution
ডায়াপ

1
1.119s প্রায় 59 এর গতিপথ তৈরি করছে!

1
হ্যাঁ, আমি কেবল এটি উল্লেখ করতে চেয়েছিলাম। আমার পক্ষে কেবল সি ++ তে স্ট্যান্ডার্ড লাইব্রেরি PRNG- র কিছু চেষ্টা করা সহজ ছিল। মনে রাখবেন যে আপনি 8 টি এন্ট্রি তৈরি করতে PRNG থেকে একটি 32-বিট পূর্ণসংখ্যার ফলাফল ব্যবহার করতে পারেন F
ডায়াপ

1
যেহেতু nসমান 8, আপনি সম্ভবত যথাযথ Sস্টোরেজ সহ ডটপ্রডাক্ট গণনা করতে AVX (বা 2 * এসএসই) ব্যবহার করতে পারেন ।
মাইকেল এম।

2
এসএসই সংস্করণ, ছোট গতি বৃদ্ধি: gist.github.com/anonymous/11394210 (অন্তর্ভুক্ত করতে ভুলবেন না smmintrin.h)
মাইকেল এম

5

পার্ল

এটি সি এর সমাধানের মতো দ্রুততর কাছাকাছি কোথাও নেই, তবে আমার মনে হয় এমন উচ্চ-স্তরের ব্যাখ্যিত ভাষার জন্য এটি খুব দ্রুত। এটি পাইথন বাস্তবায়নের চলমান সময় থেকে প্রায় 40% শেভ করে।

#!/usr/bin/env perl

use v5.10;
use strict;
use warnings;
use Algorithm::Combinatorics qw( variations_with_repetition );
use List::Util qw( any sum );

use constant {
  N        => 8,
  M        => 8,
  ITERS    => 1000,
};

my @leadingzerocounts;

my $variations = variations_with_repetition([-1, 1], N + M - 1);
while (my $S = $variations->next)
{
  for my $i (1 .. ITERS)
  {
    my @F;
    until (@F and any { $_ } @F)
    {
      @F = map +((-1,0,0,1)[rand 4]), 1..N;
    }

    my $j = 0;
    while ($j < M)
    {
      last if sum map $F[$_]*$S->[$j+$_], 0..N-1;
      $leadingzerocounts[$j++]++;
    }
  }
}

say join ", ", @leadingzerocounts;

অ্যালগরিদম :: সংযুক্তি উবুন্টু ( sudo apt-get install libalgorithm-combinatorics-perl) এ উপলব্ধ। ব্যবহৃত অন্যান্য মডিউলগুলি হ'ল মূল পার্ল মডিউল, সুতরাং ইতিমধ্যে উবুন্টু ইনস্টলেশনের অংশ হিসাবে ইতিমধ্যে ইনস্টল করা উচিত।


1
এটি গতিকে প্রভাবিত করবে না, তবে এটি 0..N-1শেষের মধ্যে রয়েছে map, তাই না? আপনি কি ভুলে গেছেন use warnings? :-) যদিও ওপিতে যুক্তি বিভ্রান্তিকর, স্লাইডিং উইন্ডো কখনই শেষ উপাদানটিতে যায় না S
ব্যবহারকারী 2846289

আহ। আমি কেবল অনুভব করেছি যে অ্যারেগুলি মেলানো মাপের ছিল তাই আমি warningsঅনুপস্থিত উপাদানগুলিকে শূন্য হিসাবে বিবেচনা করার অনুমতি দিয়ে অক্ষম করেছি । N-1এটি উন্নতি করে। এবং এটি আসলে গতিটি খুব সামান্য উন্নতি করে - এটি পাইথন বাস্তবায়নের চেয়ে প্রায় 40% দ্রুত faster
tobyink

আমি মনে করি আপনার কোডটির জন্য তালিকা :: ইউটিলের খুব আধুনিক সংস্করণ প্রয়োজন। উবুন্টুতে 14.04 এ আমি পেয়েছি "যে কোনও" তালিকা দ্বারা রফতানি করা হয় না: ইউটিউল মডিউল

ওহ হ্যাঁ, এটি সত্য - আপনাকে সম্ভবত সিপিএএন বন্ধ তালিকা তৈরি করতে হবে। anyবিকল্পভাবে তালিকা :: MoreUtils এ পাওয়া যাবে, যদিও মূল মডিউলটি সর্বাধিক ব্যবহৃত সিপিএএন মডিউলগুলির মধ্যে একটি নয়।
tobyink

4

জুলিয়া: 4.66x ধীর!

আমি সত্যিই তাদের ওয়েবসাইটে পরিসংখ্যান সন্দেহ করতে শুরু করছি ...

নোট করুন যে নীচের জুলিয়া কোডটি কার্যকরভাবে কোনও অপ্টিমাইজেশন ছাড়াই অপির পাইথন কোডের সরাসরি প্রতিলিপি। time()জুলিয়ার ধীর প্রারম্ভিক সময় বাদ দিতে আমি ফাংশনটি ব্যবহার করি ...

srand(27182818284590)
t = time()

require("Iterators")

n = 8
m = 8
iters = 1000
bothzero = 0
leadingzerocounts = zeros(m)

for S in Iterators.product(fill([-1,1], n+m-1)...)
    for i = 1:iters
        F = [[-1 0 0 1][rand(1:4)] for j = 1:n]
        while all((x) -> x == 0, F)
            F = [[-1 0 0 1][rand(1:4)] for j = 1:n]
        end
        j = 1
        while j <= m && sum(map(*, F, S[j:j+n-1])) == 0
            leadingzerocounts[j] += 1
            j += 1
        end
    end
end

println(leadingzerocounts)

t = time() - t
println("$t seconds")

জুলিয়া: 5 মি 32.912 এস

পাইপাইতে ওপির কোড: 1 মি। 11.506 এস

জুলিয়া আউটপুট:

6332170
2525472
1041522
438761
193119
86873
40705
19662

7
আপনার <s> নির্লজ্জ </ strong> ক্রীড়াবিদ জন্য +1।
#_HongKongInd dependence

গ্লোবাল ভেরিয়েবল, আমদানি এবং অ্যারে বোঝা ধীর are পারফরম্যান্সের জন্য কেউ সাধারণত কোনও জুলিয়া প্রোগ্রাম লিখতে পারে না।
অ্যালেক্স এ।

4

RPython 0.187s (258x দ্রুত)

আসল উত্স ডাব্লু / পাইপাই 2.2.1: 1 মি 6.718 সে

থ্রেডিংয়ের সাথে, স্ট্যান্ডার্ড পাইথনের ব্যাক-সাপোর্ট বাদ দেওয়া হয়েছে। কমান্ড লাইন প্যারামিটার হিসাবে কর্মী থ্রেডের সংখ্যা নির্দিষ্ট করা যেতে পারে, ডিফল্ট দুটি হয়।

from time import time, sleep
from math import fmod

from rpython.rlib.rthread import start_new_thread, allocate_lock, get_ident
class Random:
  __slots__ = ['s']

  def __init__(self, s=1):
    self.s = s

  def init_genrand(self, seed):
    self.s = seed

  def genrand32(self):
    # xorshift PRNG with period 2^32-1
    # see http://core.kmi.open.ac.uk/download/pdf/6250138.pdf
    self.s ^= (self.s << 13)
    self.s ^= (self.s >> 17)
    self.s ^= (self.s << 5)
    return self.s

class ThreadEnv:
  __slots__ = ['n', 'm', 'iters', 'counts', 'running', 'lock']

  def __init__(self):
    self.n = 8
    self.m = 8
    self.iters = 1000
    self.counts = [0]*8
    self.running = 0
    self.lock = None

env = ThreadEnv()
truth = [-1,0,0,1]

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

  if argc == 5:
    num_threads = int(argv[4])
  else:
    num_threads = 2

  env.n = int(argv[1])
  env.m = int(argv[2])
  env.iters = int(argv[3]) // num_threads
  env.counts = [0]*env.m
  env.lock = allocate_lock()

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

  env.running += 1

  # use the main process as a worker
  run()

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

  print env.counts
  return 0

def run():
  n, m, iters = env.n, env.m, env.iters
  counts = [0]*m
  sbits = [0]*(n+m-1)

  random = Random()
  seed = int(fmod(time(), 2147483.648)*1000) ^ get_ident()
  random.init_genrand(seed)

  for S in xrange(1<<n+m-1):
    i = 0
    sbit = 0
    while not sbit:
      sbits[i] ^= 3
      sbit = sbits[i]
      i += 1

    for i in xrange(iters):
      f = 0
      while not f:
        F = random.genrand32()

        G, x = F, 0
        for k in xrange(n):
          x += truth[(G&3)^sbits[k]]
          f |= x
          G >>= 2

      if not x:
        counts[0] += 1
        for j in xrange(1, m):
          G, x = F, 0
          for k in xrange(j, n+j):
            x += truth[(G&3)^sbits[k]]
            G >>= 2
          if x: break
          counts[j] += 1

  # passing True stalls until a lock can be obtained
  env.lock.acquire(True)

  for i in xrange(m):
    env.counts[i] += counts[i]
  env.running -= 1

  env.lock.release()

def target(*args):
  return main, None

আরপিথন পাইথনের একটি সীমাবদ্ধ উপসেট, যা সিতে অনুবাদ করা যায় এবং তারপরে আরপিথন টুলচেন ব্যবহার করে সংকলিত হতে পারে । এর প্রকাশিত উদ্দেশ্য ভাষা দোভাষী তৈরিতে সহায়তা করা, তবে এটি উপরের মতো সাধারণ প্রোগ্রামগুলি সংকলন করতেও ব্যবহার করা যেতে পারে। পাইথনের বেশিরভাগ 'ফ্যানসিয়ার' বৈশিষ্ট্য যেমন itertoolsবা এমনকি mapপাওয়া যায় না।

সংকলন করতে, বর্তমান পাইপির সংগ্রহস্থলের স্থানীয় ক্লোন তৈরি করুন এবং নিম্নলিখিতটি চালান:

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

ফলস্বরূপ এক্সিকিউটেবলের নাম convolution-cবা বর্তমান চলমান ডিরেক্টরিতে অনুরূপ।

আমি ইনপুট ভেরিয়েবলগুলিকে প্যারামিটারাইজ করেছি, সুতরাং প্রোগ্রামটি এইভাবে চালানো উচিত:

convolution-c 8 8 1000

নমুনা কোড মেলে।


বাস্তবায়ন নোট

S in itertools.product([-1,1], repeat = n+m-1)হয়ে যায় S in xrange(1<<n+m-1), Sএকটি বিট মানচিত্র হিসাবে ব্যাখ্যা : [ 0, 1] → [ -1, 1]

অনুরূপভাবে, Fএকটি বিট মানচিত্র, একটি একক মান প্রতিনিধিত্বমূলক প্রতিটি দুই বিটের সাথে হল:
[ 00, 01, 10, 11] → [ -1, 0, 0, 1]

একটি সত্য টেবিলটি মাল্টিপ্লিকেশন সম্পাদন করার পরিবর্তে পণ্যটি অনুসন্ধান করতে ব্যবহৃত হয়।

কারণ 32-বিট স্বাক্ষরিত পূর্ণসংখ্যার ব্যবহার করা হয়, n15 n+mটির চেয়ে বড় এবং 31 এর চেয়ে বড় আর না rpython.rlib.rbigint। প্রয়োজনে মডিউলের মাধ্যমে স্বেচ্ছাসেবী পূর্ণসংখ্যার সমর্থন অর্জন করা যায় ।

ডট-প্রোডাক্ট লুপের প্রথম পুনরাবৃত্তিটি অনিয়ন্ত্রিত, এবং এর শূন্যতার পরীক্ষার সাথে মিলিত F

একটি হোমব্রু PRNG ব্যবহৃত হয়, উত্স তালিকাভুক্ত listed কাগজের লেখক 2 32 -1 এর সময়কালের চিত্র প্রদর্শন করে এবং দাবি করেছে যে এটি সমস্ত ডিহার্ড পরীক্ষাগুলি একটি করে সংরক্ষণ করে, যদিও আমি ব্যক্তিগতভাবে এটি নিশ্চিত করে নি।

এলোমেলো বীজ প্রতি মিলিসেকেন্ডে পরিবর্তিত হয়, যা টাইমস্ট্যাম্প ব্যবহারের মতো উপযুক্ত। অতিরিক্তভাবে, প্রতিটি কর্মী প্রতিটি xorতাদের আলাদা আলাদা বীজ রয়েছে তা নিশ্চিত করার জন্য, এই মান সহ তাদের প্রক্রিয়া আইডি থ্রেড করে ।


নমুনা সময়

2 কর্মী থ্রেড:

$ timeit convolution-c 8 8 1000 2
[6331845, 2526161, 1042330, 440018, 193724, 87147, 40943, 19603]

Elapsed Time:     0:00:00.375
Process Time:     0:00:00.687
System Calls:     6927

4 কর্মী থ্রেড:

$ timeit convolution-c 8 8 1000 4
[6334565, 2527684, 1043502, 440216, 193225, 87398, 40799, 19338]

Elapsed Time:     0:00:00.218
Process Time:     0:00:00.796
System Calls:     3417

8 কর্মী থ্রেড:

$ timeit convolution-c 8 8 1000 8
[6327639, 2522483, 1039869, 437884, 192460, 86771, 40420, 19403]

Elapsed Time:     0:00:00.187
Process Time:     0:00:00.734
System Calls:     3165

ওপির আসল উত্স:

$ timeit pypy convolution-orig.py
[6330610, 2525644, 1041481, 438980, 193001, 86622, 40598, 19449]

Elapsed Time:     0:01:06.718
Process Time:     0:01:06.718
System Calls:     11599808

100000 পুনরাবৃত্তির সময়:

$ timeit convolution-c 8 8 100000 8
[633156171, 252540679, 104129386, 43903716, 19307215, 8709157, 4072133, 1959124]

Elapsed Time:     0:00:16.625
Process Time:     0:01:02.406
System Calls:     171341

এর আগে আরপিথন প্রোগ্রাম আমি কখনও দেখিনি। এটা অসাধারণ. এখন কি সমমানের খাঁটি পাইথন প্রোগ্রাম রয়েছে যা পাইপি 1.03s সালে চালাতে পারে?

@ ল্যাম্বিক আমি একটি দেখতে চাই আমি ভেবেছিলাম 4.7s বেশ ভাল ছিল, বিবেচনা করে খাঁটি পাইথনটিতে আমার প্রথম প্রচেষ্টাটি 15 ডলার ছিল।
প্রিমো

হ্যাঁ, বিলম্বের জন্য দুঃখিত। কোডটি এখনও চলছে না তবে যত তাড়াতাড়ি সম্ভব হবে।

আপনার একটি জেআইটি যুক্ত করার চেষ্টা করা উচিত। এখন যে দ্রুত হবে!
kirbyfan64sos

@ ল্যাম্বিক উল্লেখ করার জন্য ধন্যবাদ;) কৌতূহলবশত, এটি কি 4 কর্মী থ্রেড, বা 8 দিয়ে সবচেয়ে দ্রুত চালিত?
প্রাইমো

3

জুলিয়া: 1 মিনিট 21.4 সে (দ্রুত 2.2x) (আরমানের কোড পরিবর্তন)

পাইপাইতে অপের কোড: 3 মিনিট 1.4 এস

দুটিই প্যাকেজ লোড করার সময় অন্তর্ভুক্ত না করেই আরপিএলে সম্পন্ন হয়েছে।

function foo()                                                                                                                                                             
    n = 8                                                                                                                                                                  
    m = 8                                                                                                                                                                  
    iters = 1000                                                                                                                                                           
    bothzero = 0                                                                                                                                                           
    leadingzerocounts = zeros(Int,m)                                                                                                                                       
    P=[-1,0,0,1]                                                                                                                                                           

    for S in Iterators.product(fill([-1,1], n+m-1)...)                                                                                                                     
        Sm=[S...]                                                                                                                                                          
        for i = 1:iters                                                                                                                                                    
            F = P[rand(1:4,n)]                                                                                                                                             
            while all(F==0)                                                                                                                                                
                F = P[rand(1:4,n)]                                                                                                                                         
            end                                                                                                                                                            
            j = 1                                                                                                                                                          

            while j <= m && dot(F,Sm[j:j+n-1]) == 0                                                                                                                        
                leadingzerocounts[j] += 1                                                                                                                                  
                j += 1                                                                                                                                                     
            end                                                                                                                                                            
        end                                                                                                                                                                
    end                                                                                                                                                                    

    println(leadingzerocounts)                                                                                                                                             
end 

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

এটি কেবল বিন্দু (x, y) এর পরিবর্তে ডট পণ্য হিসাবে যোগফল (মানচিত্র (*, x, y)) ব্যবহার করে। 10k ডাবলসের ভেক্টরের জন্য 650 গুণ প্রথম সংস্করণ ধীর । এবং ডট পণ্য ফাংশন খাঁটি জুলিয়ায় লুপ হিসাবে প্রয়োগ করা হয়।

এছাড়াও, অ্যারে বোঝা ধীর হয় are জে = 1: এন এর জন্য [[-1 0 0 1] [র‌্যান্ড (1: 4)] এর পরিবর্তে [0,1,0, -1] [র‌্যান্ড (1: 4, n)] লেখাই ভাল is ।

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


ধন্যবাদ! আমি দেখতে পাচ্ছি যে জুলিয়া ভাষা সম্পর্কে গতি সম্পর্কে দাবি করাতে যাওয়ার আগে আমার কাছে এখনও কিছুটা শিখতে হবে :) সত্যিই খুব খুশি যে আমার কোডে কয়েকটি তুচ্ছ ফিক্সগুলি কার্যকর করার সময়টিকে কয়েক গুণ বাড়িয়ে দেয়।
নিমিম আগর

2

নমরূদ

import times, locks, strutils, unsigned

const
  N = 8
  M = 8
  iters = 1000
  numThreads = 8

type
  SVec = array[0..N+M-1, int]
  FVec = array[0..N-1, int]
  ComputeThread = TThread[int]

var
  rngSeed = int(epochTime()*1000)
  totalLeadingZeros: array[0..M-1, int]
  lock: TLock

type
  RNGState = object
    x, y, z, w: uint32

proc newRNG(seed: int): RNGState =
  result.x = uint32(seed)

proc random(rng: var RNGState): int =
  let t = rng.x xor (rng.x shl 11)
  rng.x = rng.y; rng.y = rng.z; rng.z = rng.w
  rng.w = rng.w xor (rng.w shr 19) xor t xor (t shr 8)
  result = int(rng.w)

proc initVecRand(v: var FVec, rng: var RNGState) =
  const values = [ -1, 0, 0, 1 ]
  var rnd = rng.random
  var bitAcc = 0
  for i in 0 .. <len(v):
    let val = values[rnd and 3]
    rnd = rnd shr 2
    v[i] = val
    bitAcc = bitAcc or val
  if bitAcc == 0:
    initVecRand(v, rng)

proc convolve(s: SVec, f: FVec, offset: int): int =
  for i in 0 .. <len(f):
    result += s[i+offset]*f[i]

proc iterate(v: var SVec) =
  for i in 0 .. <len(v):
    if v[i] == -1:
      v[i] = 1
      return
    v[i] = -1

proc mainThread(id: int) {.thread.} =
  const numS = 1 shl (N+M-1)
  var
    s: SVec
    f: FVec
    leadingZeros: array[0..M-1, int]
    rng = newRNG(rngSeed + id)
  for k in 0 .. <len(s):
    s[k] = -1
  for i in 1..numS:
    for j in countUp(id, iters, numThreads):
      initVecRand(f, rng)
      if convolve(s, f, 0) == 0:
        leadingZeros[0] += 1
        for k in 1 .. <M:
          if convolve(s, f, k) == 0:
            leadingZeros[k] += 1
          else:
            break
    iterate(s)
  acquire(lock)
  for i in 0 .. <M:
    totalLeadingZeros[i] += leadingZeros[i]
  release(lock)

proc main =
  let startTime = epochTime()
  var threads: array[1..numThreads, ComputeThread]
  initLock(lock)
  for i in 1..numThreads:
    createThread(threads[i], mainThread, i)
  for i in 1..numThreads:
    joinThread(threads[i])
  echo("Leading zeros: ", @totalLeadingZeros)
  let endTime = epochTime()
  echo("Time taken:    ", formatFloat(endTime - startTime, ffDecimal, 3),
       " seconds")

main()

উদাহরণ আউটপুট:

Leading zeros: @[6333025, 2525808, 1042466, 439138, 192391, 86751, 40671, 19525]
Time taken:    0.145 seconds

নিম্রোদ সি-তে সংকলন করে, তাই ব্যাক-এন্ড বিষয়গুলির জন্য সি সংকলকের পছন্দও।

ঝাঁকুনি ব্যবহার করে এর সাথে সংকলন করুন:

nimrod cc --threads:on --cc=clang --passc:-flto -d:release conv.nim

জিসিসি ব্যবহার করে এর সাথে সংকলন করুন:

nimrod cc --threads:on --cc=gcc --passc:-flto -d:release conv.nim

বর্জন করা --passc:-fltoযদি আপনি একটি পুরোনো সি কম্পাইলার যে LTO সমর্থন করে না আছে। --cc=...আপনি যদি সি সংকলকটির জন্য ডিফল্ট পছন্দটি ঠিক করেন তবে বিকল্পটি ছাড়ুন । কোডটির জন্য নিম্রড ০.৯.৪ বা 0.9.5 প্রয়োজন

আমার কোয়াডকোয়ার আইম্যাকে (২.6666 গিগাহার্টজ কোর আই ৫) পিপিপি ২.২.১ (অর্থাৎ ৫০০+ বার স্পিডআপ) এর 88 সেকেন্ডের তুলনায় কোডটি জি.সি.সি. 4.9, .16 সেকেন্ডের সাথে প্রায় .15 সেকেন্ডে চলে। দুর্ভাগ্যক্রমে, আমার কাছে চারটি কোরের বেশি মেশিনে অ্যাক্সেস নেই যা পাইপাই ইনস্টল করেছে বা আমি সহজেই পাইপাই ইনস্টল করতে পারি, যদিও আমি 64৪-কোর এএমডি-তে প্রায় 1 সেকেন্ড (অনেক পরিমাপের শব্দ সহ) পাই get ওসিটারন 6376 1.4 গিগাহার্টজ (অনুযায়ী / proc / cpuinfo অনুযায়ী) gcc 4.4.6।

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


আপনি উবুন্টুর জন্য নিম্রড কীভাবে পাবেন?

@ ল্যাম্বিক একটি দ্রুত গুগল অনুসন্ধান আপনাকে নিম্রড-lang.org/download.html
এসহং

@ আমি লিঙ্কটি আমার পোস্টে অন্তর্ভুক্ত করেছিলাম (যদিও এখন এটি কালো রঙের সাথে নীল দিয়ে দেখা মুশকিল)।
রিমার বেহরেন্ডস

আপনি বীজের আকার 128 বিট বাড়িয়ে আরও বেশি গতি অর্জন করতে পারেন: xorshift.di.unimi.it
ব্যবহারকারী 60561

2

জাভা

আমি উপরের সি ++ সমাধানটি জাভায় অনুবাদ করেছি:

import java.util.Random;
import java.util.Arrays;

public class Bench2 {
  public static int[] bits = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF };
  public static int[] oneValues = { 1, 0, 0, 1 };
  public static int[] values = { -1, 0, 0, 1 };
  public static int n = 8;
  public static int m = 8;
  public static int iters = 1000;

  private static int x,y=34353,z=57768,w=1564;

  public static void main( String[] args ) {
    x = (int) (System.currentTimeMillis()/1000l);

    int[] leadingzerocounts = new int[ m ];
    Arrays.fill( leadingzerocounts, 0 );

    int maxS = 1 << 15;

    for( int s = 0; s < maxS; s++ ) {
      int x = interleaveBit( s );

      for( int i=0; i<iters; i++ ) {
        int random;

        do {
          random = 0xFFFF & fastRandom( );
        } while( sumOnes( random ) == 0 );

        int j = 7;

        while( j >= 0 ) {
          int h = ( x >> (j*2) );
          int l = 0xFFFF & (~(random ^ h));

          if( sumArray( l ) == 0 ) {
            leadingzerocounts[ j ]++;
          } else {
            break;
          }

          j--;
        }
      }
    }

    for( int i = 7; i >= 0; --i ) {
      System.out.print( leadingzerocounts[ i ] + " " );
    }

    System.out.println( );
  }

  public static int interleaveBit( int x ) {
    x = (x | ( x << 8)) & bits[3];
    x = (x | ( x << 4)) & bits[2];
    x = (x | ( x << 2)) & bits[1];
    x = (x | ( x << 1)) & bits[0];
    return x | (x << 1);
  }

  public static int sumOnes( int v ) {
    return (0xAAAA & (v ^ ~(v << 1)));
    // int s = 0;

    // for( int i = 0; i < 8; ++i ) {
    //   int a = 3 & ( v >> (i*2) );
    //   s += oneValues[ a ];
    // }

    // return s;
  }

  public static int sumArray( int v ) {
    return Integer.bitCount( v ) - 8;
    // int s = 0;

    // for( int i=0; i<8; ++i ) {
    //   int a = 3 & ( v >> (i*2) );
    //   s += values[ a ];
    // }

    // return s;
  }

  public static int fastRandom( ) {
    long t;
    t = x ^ (x << 11);
    x = y; y = z; z = w;
    return w = (int)( w ^ (w >> 19) ^ t ^ (t >> 8));
  }
}

আমার মেশিনে আমি জাভা প্রোগ্রামটির জন্য নিম্নলিখিত ফলাফল পেতে পারি:

time java Bench2
6330616 2524569 1040372 439615 193290 87131 40651 19607 
java Bench2  0.36s user 0.02s system 102% cpu 0.371 total

আমার কম্পিউটারে ওপিএস প্রোগ্রামটি প্রায় 53 সেকেন্ড চলে:

time pypy start.py
[6330944, 2524897, 1040621, 439317, 192731, 86850, 40830, 19555]
pypy start.py  52.96s user 0.06s system 99% cpu 53.271 total

সি ++ প্রোগ্রামটি প্রায় 0.15 সেকেন্ডে চালিত হয়েছিল:

time ./benchcc
[6112256, 2461184, 1025152, 435584, 193376, 87400, 40924, 19700]
./benchcc  0.15s user 0.00s system 99% cpu 0.151 total

এটি সম্পর্কিত জাভা সমাধানের তুলনায় প্রায় 2.5x গতি (আমি ভিএম স্টার্টআপ বাদ দিইনি)। এই জাভা সমাধানগুলি পাইপাই দিয়ে চালিত প্রোগ্রামের চেয়ে প্রায় 142x দ্রুত।

যেহেতু আমি ব্যক্তিগতভাবে আগ্রহী ছিলাম, তাই আমি itersজাভা এবং সি ++ এর জন্য 100_000 সেট করেছিলাম তবে কিছু বড় হয়ে গেলে 2.5 এর ফ্যাক্টর জাভাটির পক্ষে কমেনি।

সম্পাদনা: আমি একটি 64 বিট আর্ক লিনাক্স পিসিতে প্রোগ্রামগুলি চালিয়েছি ran

সম্পাদনা 2: আমি যুক্ত করতে চাই যে আমি পাইথন কোডের মোটামুটি অনুবাদ দিয়ে শুরু করেছি:

import java.util.Random;
import java.util.Arrays;

public class Bench {
    public static int[] values = { -1, 0, 0, 1 };
    public static int n = 8;
    public static int m = 8;
    public static int iters = 1000;

    private static int x,y=34353,z=57768,w=1564; 

    public static void main( String[] args ) {
        x = (int) (System.currentTimeMillis()/1000l);

        int[] leadingzerocounts = new int[ m ];
        Arrays.fill( leadingzerocounts, 0 );

        int[] S = new int[ n+m-1 ];
        Arrays.fill( S, -1 );

        do {
            for( int i=0; i<iters; i++ ) {
                int[] F = new int[ n ];

                do {
                    randomArray( F );
                } while( containsOnlyZeros( F ) );

                for( int j=0; j < m && check( F, S, j ); j++ ) {
                    leadingzerocounts[ j ] += 1;
                }
            }
        } while( next( S ) );

        System.out.println( Arrays.toString( leadingzerocounts ) );
    }

    public static void randomArray( int[] F ) {
        for( int i = 0; i<F.length; i++ ) {
            F[ i ] = (1-(fastRandom()&3))%2;
        }
    }

    public static boolean containsOnlyZeros( int[] F ) {
        for( int x : F ) {
            if( x != 0 ) {
                return false;
            }
        }

        return true;
    }

    public static boolean next( int[] S ) {
        for( int i=0; i<S.length; i++ ) {
            if( ( S[ i ] = -S[ i ] ) == 1 ) {
                return true;    
            }
        }

        return false;
    }

    public static boolean check( int[] F, int[] S, int j ) {
      int sum = 0;

      for( int i=0; i<n; i++ ) {
          sum += F[ i ] * S[ j + i ];
      }

      return sum == 0;
    }

    public static int fastRandom( ) {
        long t;
        t = x ^ (x << 11);
        x = y; y = z; z = w;
        return w = (int)( w ^ (w >> 19) ^ t ^ (t >> 8));
    }
}

এই প্রোগ্রামটি প্রায় 3.6 সেকেন্ডে চলেছিল:

time java Bench   
[6330034, 2524369, 1040723, 439261, 193673, 87338, 40840, 19567]
java Bench  3.64s user 0.01s system 101% cpu 3.600 total

যা পাইপাই সমাধানের চেয়ে প্রায় 14 গুণ বেশি দ্রুত। (দ্রুততম র্যান্ডম ফাংশনের উপর স্ট্যান্ডার্ড এলোমেলো ফাংশন নির্বাচন করা কার্যকরভাবে 5 সেকেন্ডের সময় কার্যকর করে)


2

পাইথন 3.5 + নম্পুটে 1.10.1, 3.76 সেকেন্ড

পরীক্ষাগুলি আমার ম্যাকবুক প্রোতে চালানো হয়েছিল। ওপির কোডটি একই মেশিনে ~ 6 মিনিট সময় নেয়।

আমি আসলে এই প্রশ্নের উত্তর দিচ্ছি কারণ আমার 10 টি খ্যাতি নেই এবং আমি প্রথম অংশের উত্তর দিতে পারি না :-p

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

def test_convolv():
    n = 8 
    m  = 8 
    iters = 1000
    ilow = np.ceil(0+n/2).astype(int)
    ihigh = np.ceil(m+n/2).astype(int)

    leadingzerocounts = np.zeros(m)

    # Pre-compute S & F
    S = np.array(list(itertools.product([-1,1], repeat = n+m-1)))
    choicesF = np.random.choice(np.array([-1, 0, 0, 1], dtype=np.int8), size=n*iters).reshape(iters,n)
    imask = ~np.any(choicesF, axis=1)
    while np.any(imask):
        imasksize = np.count_nonzero(imask)
        choicesF[imask,:] = np.random.choice(np.array([-1, 0, 0, 1], dtype=np.int8), size=n*imasksize).reshape(imasksize, n)
        imask = ~np.any(choicesF, axis=1)

    for i in np.arange(iters):
        F = choicesF[i, :]
        # This is where the magic is: by flattening the S array, 
        # I try to take advantage of speed of the np.convolve 
        # (really numpy.multiarray.correlate). 
        FS = (np.convolve(S.reshape(-1), F, 'same').reshape(S.shape))[:, ilow:ihigh]
        jmask_not = (FS[:, 0] != 0)
        leadingzerocounts[0] = leadingzerocounts[0]+np.count_nonzero(~jmask_not)
        for j in np.arange(n-1)+1:
            jmask = (FS[jmask_not, j] != 0)
            leadingzerocounts[j] = leadingzerocounts[j] + np.count_nonzero(~jmask)
            jmask_not[(jmask_not.nonzero()[0])[jmask]] = False

    print(leadingzerocounts)

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

আমার ম্যাকবুক প্রোতে, পরীক্ষার ফলাফলগুলি 3.76 সেকেন্ড দেয় । আমি যখন ওপির কোডটি (পাইথন 3.5 তে পরিবর্তিত) চালিয়েছি, তখন আমার প্রায় 6 মিনিট সময় পেল । স্পিডআপটি প্রায় 100 গুণ।

একটি অসুবিধা হ'ল যেহেতু এস এবং এফ অ্যারেগুলি সংরক্ষণ করতে হয়, মাপগুলি খুব বড় হলে মেমরির প্রয়োজনীয়তা একটি সমস্যা হতে পারে।

আমি প্রথম পর্বটি একই পদ্ধতি ব্যবহার করেছি এবং আমি আমার ল্যাপটপে একটি ~ 60-100x স্পিডআপ পেয়েছি।

আমি যেমন আমার ম্যাকবুক প্রোতে সব করেছি, কেউ যদি আমার কোড পরীক্ষা করতে পারে এবং আপনার মেশিনে এটি কীভাবে চলে যায় তা আমাকে জানাতে পারে, আমি এটির খুব প্রশংসা করব!


1

J, 130x ~ 50x স্পিডআপ ?

n =: m =: 8
len =: 1000
S =: (] - 0 = ])S0=: #:i.2^<:+/n,m
k =: (n#0) -.~ (_1 0 0 1) {~ (n#4) #: i.4^n
sn =: (]-0=])#:i.2^n
ku =: ~. k
M =: 0=+/"1 sn *"1/ ku
fs =: (ku&i.)"1 k
snum =: n #.\"1 S0

run =: 3 : 0
 r =: n#0
 for_t. (snum) do.
   rn =: fs{~? len # #k
   r =: r + +/"1*/\rn{"1 t{M
 end.
 r
)
echo run 0
exit''

এলোমেলো ডেবিয়ানের সময়:

u#>time j slowpy.ijs
6334123 2526955 1041600 440039 193567 87321 40754 19714

real    0m2.453s
user    0m2.368s
sys     0m0.084s


u#>time python slow_pyth.py
[6331017, 2524166, 1041731, 438731, 193599, 87578, 40919, 19705]

real    5m25.541s
user    5m25.548s
sys     0m0.012s

আমি মনে করি উন্নতির কোন জায়গা আছে।


পাইথন স্ক্রিপ্টটি ব্যবহার করে মৃত্যুদন্ড কার্যকর করার কথা pypy, এটি নয় python, এ কারণেই মনে হয় যে আপনার স্ক্রিপ্টটি ১৩০ এক্স স্পিড-আপ দিচ্ছে।
#HongKongInd dependence

@ অন্যদিকে হ্যাঁ আমি লক্ষ্য করেছি তবে আমি পাইপাই ইনস্টল করতে পারছি না: - / আমি মনে করি প্রস্থের ক্রমটি এখনও থাকবে।
এলেভেক্স


অবশ্যই, অগত্যা।
এলেভেক্স

পাইপি ইনস্টল করতে আপনার কী সমস্যা?

1

সি ++: x200 (4-কোর আই 7, 8-কোরের উপর x400 স্কেল করা উচিত)

সমান্তরালকরণের সাথে আরও সহজ-সরল সি ++ 11 (ভিএস 2012, জিসিসি এবং ঝনঝন দিয়ে পরীক্ষিত) সমাধানের জন্য চেষ্টা করা।

এটি জিসিসি ৪.৮.১ সহ লিনাক্সের অধীনে সংকলন করতে এবং চালাতে:

g ++ -O3 -msse -msse2 -msse3 -march = नेटটিস্ট -std = সি ++ 11-অধ্যায় -Wl, - প্রয়োজন নেই গল্ফ.cpp

লিনাক্সের অধীনে আমাদের std::launch::asyncএকাধিক থ্রেড জোর করা দরকার । আমি এটি আগের সংস্করণে হারিয়েছিলাম।

ভিজ্যুয়াল স্টুডিওতে (২০১২+) এটি কেবলমাত্র কাজ করা উচিত তবে সময়ের জন্য একটি রিলিজ তৈরি করা উচিত ...

আমার পুরাতন দ্বৈত কোর i3 এ এটি ~ 0.9 সেকেন্ডে চলে। আমার আই 7 কোয়াড কোর এটি 0.319s বনাম পিপাই 66 সেকেন্ড।

একটি 8-কোর i7 এ এটি x400 স্পিডআপ ব্যাপ্তির মধ্যে হওয়া উচিত। সি স্টাইল অ্যারেগুলিতে স্যুইচ করা এটির গতি বাড়িয়ে দেবে তবে আমি সি ++ ধারকগুলির সাথে থাকতে আগ্রহী। আমার পক্ষে এটি আকর্ষণীয় যে সমস্যা ডোমেনের তুলনায় তুলনামূলকভাবে কাছাকাছি থাকতে এবং তুলনামূলকভাবে উচ্চ স্তরে থাকাকালীন আপনি যে গতি অর্জন করতে পারবেন তা দেখতে আকর্ষণীয়, আমার মনে হয় সি ++ আসলেই খুব ভাল। এছাড়াও নোটটি হ'ল সি ++ 11 কনস্ট্রাক্ট ব্যবহার করে সমান্তরালতার তুলনামূলক স্বাচ্ছন্দ্য।

@ ইলমেলের বিট দ্রবণটি খুব দুর্দান্ত এবং -১০/২০১৮ এর জন্য কাজ করে। কেউ এখান থেকে এসএসইও ফেলে দিতে পারে এবং সম্ভবত একটি গুরুত্বপূর্ণ গতিপথ পেতে পারে।

সমান্তরালতার বাইরেও সেখানে আরও একটি "কৌশল" রয়েছে যা সংক্ষেপের সংখ্যা হ্রাস করে is নমুনা ফলাফল: 6332947 2525357 1041957 438353 193024 87331 40902 19649

#include <vector>
#include <iostream>
#include <thread>
#include <future>
#include <time.h>
#include <ctime>
#include <algorithm>

using namespace std;

// Bring some of these constants out to share
const size_t m = 8;
const int nthreads = 16;
const size_t cn = 15;
const int two_to_cn = 32768;

static unsigned int seed = 35;

int my_random() // not thread safe but let's call that more random!
{
   seed = seed*1664525UL + 1013904223UL; // numberical recipes, 32 bit
   return ((seed>>30)&1)-!!((seed>>30)&2); // Credit to Dave!
}

bool allzero(const vector<int>& T)
{
   for(auto x : T)
   {
      if(x!=0)
      {
         return false;
      }
   }
   return true;
}

// Return the position of the first non-zero element
size_t convolve_until_nonzero(size_t max_n, const vector<int>& v1, const vector<int>& v2)
{
   for(size_t i = 0; i<max_n; ++i)
   {
      int result = 0;
      for(size_t j = 0; j<v2.size(); ++j)
      {
         result += v1[i+j]*v2[j];
      }
      if(result!=0)
      {
         return i;
      }
   }
   return max_n;
}

void advance(vector<int>& v)
{
   for(auto &x : v)
   {
      if(x==-1)
      {
         x = 1;
         return;
      }
      x = -1;
   }
}

vector<int> convolve_random_arrays(vector<int> S, int range)
{
   const int iters = 1000;
   int bothzero = 0;
   int firstzero = 0;

   time_t current_time;
   time(&current_time);
   seed = current_time;


   vector<int> F(m);
   vector<int> leadingzerocounts(m+1);

   for(auto &x: leadingzerocounts)
   {
      x = 0;
   }

   for(int i=0; i<range; ++i)
   {
      for(int j=0; j<iters; ++j)
      {
         do
         {
            for(auto &x : F)
            {
               x = my_random();
            }
         } while(allzero(F));
         leadingzerocounts[convolve_until_nonzero(m, S, F)]++;
      }
      advance(S);
   }

   // Finish adding things up...
   for(int i=m-1; i>0; --i)
   {
      leadingzerocounts[i] += leadingzerocounts[i+1];
   }

   vector<int> withoutfirst(leadingzerocounts.begin()+1, leadingzerocounts.end());
   return withoutfirst;
}

int main(int argc, char* argv[])
{

   vector<int> leadingzerocounts(m);

   for(auto &x: leadingzerocounts)
   {
      x = 0;
   }

   clock_t start = clock();

   vector<int> S(cn);
   for(auto &x : S)
   {
      x = -1;
   }

   vector< future< vector< int > > > fs; // The future results of the threads

   // Go make threads to work on parts of the problem
   for(int i=0; i<nthreads; ++i)
   {
      vector<int> S_reversed = S; // S counts using LSBs but we want the thread start to be in MSBs
      reverse(S_reversed.begin(), S_reversed.end());
      fs.push_back(async(std::launch::async, convolve_random_arrays, S_reversed, two_to_cn/nthreads));
      advance(S);
   }
   // And now collect the data
   for(auto &f : fs)
   {
      vector<int> result = f.get();
      for(int i=0; i<result.size(); ++i)
      {
         leadingzerocounts[i] += result[i];
      }
   }

   for(auto count : leadingzerocounts)
   {
      cout << count << endl;
   }

   return 0;
}

1

ফরট্রান: 316x

ঠিক আছে, ফোরট্রান: আমি এটা পেয়েছেন 106x 155x 160x 316x যখন একটি 4 কোর i7 CPU- র উপর একটি Xorshift RNG এবং ফলে, OpenMP -র ব্যবহার speedup। তা ছাড়া বড় কোন কৌশল নেই। এসটি নির্মাণের জন্য পুনরাবৃত্তির জন্য, আমি কেবল 16-বিট পূর্ণসংখ্যা i এর বাইনারি উপস্থাপনাটি ব্যবহার করি। আপনি লক্ষ করবেন যে ইনলাইন আরএনজি এবং "পুনরায়" / আই ম্যাসেজ থেকে এস তে ম্যাপিং বাদে কোডটি পাইথন কোডের মতোই উচ্চ স্তরের।

সম্পাদনা: Xorshift এ "যদি" সরানো হয়েছে, এখন "r = w / ..." এর পরিবর্তে "r = অ্যাবস (ডাব্লু / ...)" ব্যবহার করুন। 106x থেকে 155x এ যায়।

সম্পাদনা 2: এটি সি ++ সমাধান হিসাবে 15x হিসাবে অনেক এলোমেলো সংখ্যা উত্পন্ন করে। ফরট্রানে 0 এবং 1s এর অ্যারে এলোমেলো ইনটকে রূপান্তর করার জন্য যদি কারও কাছে শূন্য ওভারহেড সমাধান থাকে তবে আমি সব কান। তারপরে আমরা সি ++ কে মারতে পারি :)

সম্পাদনা 3: লেম্বিক নির্দেশিত হিসাবে প্রথম সম্পাদনাটি একটি বাগ প্রবর্তন করেছিল। দ্রুত গতিতে সামান্য উন্নতি সহ এটি এখন ঠিক করা হয়েছে। আরও স্পীডআপ পেতে আমি ইলেভেক্সের পরামর্শটি ব্যবহার করার চেষ্টা করব।

সম্পাদনা 4: প্রোফাইলিং ইঙ্গিত দেয় যে প্রকৃত এবং ফিরে নিকট () এর সাথে পূর্ণসংখ্যায় রূপান্তর ধীর ছিল। 160x থেকে 316x স্পিডআপে গিয়ে আমি একটি পূর্ণসংখ্যা বিভাগকে স্কেলিং এবং রাউন্ডিং উভয়ের সাথে প্রতিস্থাপন করেছি।

এর সাথে সংকলন:

গফর্ট্রন -O3 -মার্চ = নেটিভ -ফোনপ গল্ফ.ফ 90

program golf
implicit none
integer, parameter :: m=8, n=8
integer :: F(n), S(m+n-1), leadingzerocounts(m)
integer :: j,k,bindec,enc,tmp,x=123456789,y=362436069,z=521288629,w=88675123
integer*2 :: i
real :: r

leadingzerocounts=0

!$OMP parallel do private(i,enc,j,bindec,S,F,k,tmp,x,y,z,w,r) reduction(+:leadingzerocounts) schedule(dynamic)
do i=0,32766
  enc=i
  ! Short loop to convert i into the array S with -1s and 1s
  do j=16,2,-1
    bindec=2**(j-1)
    if (enc-bindec .ge. 0) then
      S(j-1)=1
      enc=enc-bindec
    else
      S(j-1)=-1
    endif
  end do
  do j=1,1000
    F=0
    do while (.not. any(F /= 0))
      do k=1,n
        ! Start Xorshift RNG
        tmp = ieor(x,ishft(x,11))
        x = y
        y = z
        z = w
        w = ieor(ieor(w,ishft(w,-19)),ieor(tmp,ishft(tmp,-8)))
        ! End Xorshift RNG
        ! Just scale it inside the nint:
        !F(k)=nint(w/2147483648.0)
        ! Scaling by integer division is faster, but then we need the random 
        ! number to be in (-2,2) instead of [-1,1]:
        F(k)=w/1073741824

      end do
    end do
    do k=1,m
      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

উদাহরণ আউটপুট:

$ সময়।
/a.out 6329624 2524831 1039787 438809 193044 6860 40486 19517
./a.out 1.45s ব্যবহারকারীর 0.00s সিস্টেম 746% সিপিইউ 0.192 মোট

ওপির কোড:

$ সময় পাইপী গল্ফ.পি পিপি
গল্ফ.পি 60.68 এস ব্যবহারকারী 0.04 এস সিস্টেম 99% সিপিইউ 1: 00.74 মোট


আমি জেতে যা ব্যবহার করেছি তা বেস -4 এ 4 ^ n সংখ্যার একটি পূর্বনির্ধারিত তালিকা ছিল, তারপরে ট্রায়াডিক এবং রূপান্তরকারী 0 এ রূপান্তরিত হয়েছিল The আরএনজি কেবল এই তালিকা থেকে পছন্দ করে।
এলেভেক্স

আপনার কোডটি সঠিক কিনা তা আমি নিশ্চিত নই। 100,000 পুনরাবৃত্তির জন্য আমি 633140285 271390368 118307997 52751245 23725837 10744292 4944464 2388125 তবে আমি মনে করি এটি 633170604 252560981 104156146 43911426 19316309 8713324 4073378 1959440 এর মধ্যেই হওয়া উচিত consistent

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

এটিও তা বাড়িয়ে দিয়েছে বলে মনে হচ্ছে!

হ্যাঁ, আমার কাছে সামান্য গতিপথ আমি বুঝতে পেরেছি যে আমি 1.0 যোগ করছি এবং তারপরে একটি টান লুপের ভিতরে 1.0 বিয়োগ করছিলাম।
আধা-বহির্মুখী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.