স্থায়ী হিসাবে যত তাড়াতাড়ি সম্ভব গণনা করুন


26

চ্যালেঞ্জটি হ'ল ম্যাট্রিক্সের স্থায়ী গণনা করার জন্য দ্রুততম কোডটি লেখা ।

এক n- nমেট্রিক্সের স্থায়ী A= ( ai,j) হিসাবে সংজ্ঞায়িত করা হয়

এখানে চিত্র বর্ণনা লিখুন

এখানে S_nসমস্ত আদেশের সেটটি উপস্থাপন করে [1, n]

উদাহরণ হিসাবে (উইকি থেকে):

এখানে চিত্র বর্ণনা লিখুন

এই প্রশ্নে ম্যাট্রিকগুলি সমস্ত বর্গক্ষেত্র এবং কেবলমাত্র মান -1এবং সেগুলিতে থাকবে 1

উদাহরণ

ইনপুট:

[[ 1 -1 -1  1]
 [-1 -1 -1  1]
 [-1  1 -1  1]
 [ 1 -1 -1  1]]

স্থায়ী ঠিকানা:

-4

ইনপুট:

[[-1 -1 -1 -1]
 [-1  1 -1 -1]
 [ 1 -1 -1 -1]
 [ 1 -1  1 -1]]

স্থায়ী ঠিকানা:

0

ইনপুট:

[[ 1 -1  1 -1 -1 -1 -1 -1]
 [-1 -1  1  1 -1  1  1 -1]
 [ 1 -1 -1 -1 -1  1  1  1]
 [-1 -1 -1  1 -1  1  1  1]
 [ 1 -1 -1  1  1  1  1 -1]
 [-1  1 -1  1 -1  1  1 -1]
 [ 1 -1  1 -1  1 -1  1 -1]
 [-1 -1  1 -1  1  1  1  1]]

স্থায়ী ঠিকানা:

192

ইনপুট:

[[1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1],
 [1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1],
 [-1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1],
 [-1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1],
 [-1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1],
 [1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1],
 [1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1],
 [1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1],
 [1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1],
 [-1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1],
 [-1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1],
 [1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1],
 [-1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1],
 [1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1],
 [1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1],
 [1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1],
 [-1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1],
 [1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1],
 [1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1],
 [-1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1]]

স্থায়ী ঠিকানা:

1021509632

কাজটি

আপনার এমন কোড লিখতে হবে যা ম্যাট্রিক্সের nদ্বারা প্রদত্ত n, এটির স্থায়ী আউটপুট দেয়।

যেহেতু আপনার কোডটি পরীক্ষা করার দরকার হবে এটি সহায়ক হবে যদি আপনি আমাকে আপনার কোডটিতে ইনপুট হিসাবে একটি ম্যাট্রিক্স দেওয়ার সহজ উপায় দিতে পারেন, উদাহরণস্বরূপ স্ট্যান্ডার্ড ইন থেকে পড়ে।

সতর্ক হতে হবে যে স্থায়ীভাবে বড় হতে পারে (সমস্ত 1 ম্যাট্রিক্স চরম ক্ষেত্রে)।

স্কোর এবং টাই

আমি আপনার কোডটি বর্ধমান আকারের এলোমেলো + -1 ম্যাট্রিক্সে পরীক্ষা করব এবং আপনার কোডটি আমার কম্পিউটারে 1 মিনিটেরও বেশি সময় নেয় প্রথমবার বন্ধ করব। ন্যায্যতা নিশ্চিত করার জন্য স্কোরিং ম্যাট্রিকগুলি সমস্ত জমা দেওয়ার জন্য সামঞ্জস্যপূর্ণ হবে।

যদি দু'জন লোক একই স্কোর পায় তবে বিজয়ী হ'ল এটির মানটি সবচেয়ে দ্রুত n। সেগুলি যদি একে অপরের 1 সেকেন্ডের মধ্যে হয় তবে এটি প্রথমে পোস্ট করা।

ভাষা ও গ্রন্থাগার

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

রেফারেন্স বাস্তবায়ন

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

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

আমার মেশিন সম্পর্কে নিম্ন স্তরের তথ্য

cat /proc/cpuinfo/|grep flags দেয়

পতাকা: FPU vme ডি PSE টিএসসি MSR PAE MCE cx8 APIC সেপ্টেম্বর mtrr pge MCA cmov চাপড়ান pse36 clflush MMX fxsr SSE sse2 এইচটি প্রাপ্ত syscall Nx mmxext fxsr_opt pdpe1gb rdtscp LM constant_tsc rep_good nopl nonstop_tsc extd_apicid aperfmperf pni pclmulqdq নিরীক্ষণ ssse3 FMA cx16 sse4_1 sse4_2 popcnt AES xsave AVX f16c lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr tbm topoext perfctr_core perfctr_nb cpb hc_ststmm vstpcctmmvstpcctmmvppccbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmcstbmct

আমি একটি ঘনিষ্ঠভাবে সম্পর্কিত মাল্টি-ল্যাঙ্গুয়েজ প্রশ্ন জিজ্ঞাসা করব যা বড় ইন্টার সমস্যাতে ভুগছে না তাই স্কালা , নিম , জুলিয়া , মরিচা , বাশের প্রেমীরাও তাদের ভাষা বন্ধ করতে পারেন।

লিডার বোর্ড

  • n = 33 (45 = 45 সেকেন্ড। n = 34 এর জন্য 64 সেকেন্ড)। টন Hospel মধ্যে সি ++ জি ++, 5.4.0।
  • n = 32 (32 সেকেন্ড)। ডেনিস মধ্যে সি জিসিসি 5.4.0 এর মাধ্যমে ব্যবহার টন Hospel এর জিসিসি পতাকা।
  • n = 31 (54 সেকেন্ড)। খৃস্টান Sievers মধ্যে Haskell,
  • n = 31 (60 সেকেন্ড)। Primo মধ্যে rpython
  • n = 30 (26 সেকেন্ড)। ezrast মধ্যে মরচে
  • n = 28 (49 সেকেন্ড) পাইথন + পাইপ 5.4.1 এর সাথে xnor
  • n = 22 (25 সেকেন্ড)। পাইথন + পাইপি 5.4.1 সহ শেবাং

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


5
আমি প্রথম বাক্যটি পড়লাম, ভাবি 'লেম্বিক', স্ক্রোলড ডাউন, হ্যাঁ - লেম্বিক।
orlp

@orlp :) অনেক দিন হয়েছে।

1
@ ল্যাম্বিক আমি একটি বড় পরীক্ষার কেস যুক্ত করেছি। আমি এটির জন্য নিশ্চিত হয়ে কেউ অপেক্ষা করবে।
xnor

2
উত্তরগুলির মধ্যে একটি আনুমানিক ফলাফল মুদ্রণ করে, যেহেতু এটি স্থায়ী সঞ্চয় করতে ডাবল নির্ভুলতা ভাসমান ব্যবহার করে। এটা কি অনুমোদিত?
ডেনিস

1
@ ক্রিশ্চিয়িয়ানসিভারগুলি আমি ভেবেছিলাম যে আমি লক্ষণগুলি দিয়ে কিছু জাদু করতে সক্ষম হব, তবে এটি পাত্তা পেল না ...
সকরাটিক ফিনিক্স

উত্তর:


13

gcc C ++ n ≈ 36 (আমার সিস্টেমে 57 সেকেন্ড)

আপডেটের জন্য গ্রে কোড সহ গ্লেন সূত্র ব্যবহার করে যদি সমস্ত কলামের পরিমাণ সমান হয়, অন্যথায় রাইজারের পদ্ধতিটি ব্যবহার করে। থ্রেডেড এবং ভেক্টরাইজড। এভিএক্সের জন্য অনুকূলিত, তাই পুরানো প্রসেসরের উপর বেশি আশা করবেন না। n>=35স্বাক্ষরিত 128 বিট সঞ্চালক ওভারফ্লো হয়ে যাওয়ার পরেও আপনার সিস্টেমটি যথেষ্ট দ্রুত হলেও কেবলমাত্র +1 সহ কোনও ম্যাট্রিক্স নিয়ে বিরক্ত করবেন না । এলোমেলো ম্যাট্রিক্সের জন্য আপনি সম্ভবত ওভারফ্লোতে আঘাত করবেন না। জন্য n>=37অভ্যন্তরীণ multipliers একটি সব জন্য ওভারফ্লো শুরু হবে 1/-1ম্যাট্রিক্স। সুতরাং শুধুমাত্র এই প্রোগ্রামটি ব্যবহার করুন n<=36

কেবল STDIN এ ম্যাট্রিক্স উপাদানগুলি যে কোনও ধরণের সাদা স্থান দ্বারা পৃথক করে দিন

permanent
1 2
3 4
^D

permanent.cpp:

/*
  Compile using something like:
    g++ -Wall -O3 -march=native -fstrict-aliasing -std=c++11 -pthread -s permanent.cpp -o permanent
*/

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdint>
#include <climits>
#include <array>
#include <vector>
#include <thread>
#include <future>
#include <ctgmath>
#include <immintrin.h>

using namespace std;

bool const DEBUG = false;
int const CACHE = 64;

using Index  = int_fast32_t;
Index glynn;
// Number of elements in our vectors
Index const POW   = 3;
Index const ELEMS = 1 << POW;
// Over how many floats we distribute each row
Index const WIDTH = 9;
// Number of bits in the fraction part of a floating point number
int const FLOAT_MANTISSA = 23;
// Type to use for the first add/multiply phase
using Sum  = float;
using SumN = __restrict__ Sum __attribute__((vector_size(ELEMS*sizeof(Sum))));
// Type to convert to between the first and second phase
using ProdN = __restrict__ int32_t __attribute__((vector_size(ELEMS*sizeof(int32_t))));
// Type to use for the third and last multiply phase.
// Also used for the final accumulator
using Value = __int128;
using UValue = unsigned __int128;

// Wrap Value so C++ doesn't really see it and we can put it in vectors etc.
// Needed since C++ doesn't fully support __int128
struct Number {
    Number& operator+=(Number const& right) {
        value += right.value;
        return *this;
    }
    // Output the value
    void print(ostream& os, bool dbl = false) const;
    friend ostream& operator<<(ostream& os, Number const& number) {
        number.print(os);
        return os;
    }

    Value value;
};

using ms = chrono::milliseconds;

auto nr_threads = thread::hardware_concurrency();
vector<Sum> input;

// Allocate cache aligned datastructures
template<typename T>
T* alloc(size_t n) {
    T* mem = static_cast<T*>(aligned_alloc(CACHE, sizeof(T) * n));
    if (mem == nullptr) throw(bad_alloc());
    return mem;
}

// Work assigned to thread k of nr_threads threads
Number permanent_part(Index n, Index k, SumN** more) {
    uint64_t loops = (UINT64_C(1) << n) / nr_threads;
    if (glynn) loops /= 2;
    Index l = loops < ELEMS ? loops : ELEMS;
    loops /= l;
    auto from = loops * k;
    auto to   = loops * (k+1);

    if (DEBUG) cout << "From=" << from << "\n";
    uint64_t old_gray = from ^ from/2;
    uint64_t bit = 1;
    bool bits = (to-from) & 1;

    Index nn = (n+WIDTH-1)/WIDTH;
    Index ww = nn * WIDTH;
    auto column = alloc<SumN>(ww);
    for (Index i=0; i<n; ++i)
        for (Index j=0; j<ELEMS; ++j) column[i][j] = 0;
    for (Index i=n; i<ww; ++i)
        for (Index j=0; j<ELEMS; ++j) column[i][j] = 1;
    Index b;
    if (glynn) {
        b = n > POW+1 ? n - POW - 1: 0;
        auto c = n-1-b;
        for (Index k=0; k<l; k++) {
            Index gray = k ^ k/2;
            for (Index j=0; j< c; ++j)
                if (gray & 1 << j)
                    for (Index i=0; i<n; ++i)
                        column[i][k] -= input[(b+j)*n+i];
                else
                    for (Index i=0; i<n; ++i)
                        column[i][k] += input[(b+j)*n+i];
        }
        for (Index i=0; i<n; ++i)
            for (Index k=0; k<l; k++)
                column[i][k] += input[n*(n-1)+i];

        for (Index k=1; k<l; k+=2)
            column[0][k] = -column[0][k];

        for (Index i=0; i<b; ++i, bit <<= 1) {
            if (old_gray & bit) {
                bits = bits ^ 1;
                for (Index j=0; j<ww; ++j)
                    column[j] -= more[i][j];
            } else {
                for (Index j=0; j<ww; ++j)
                    column[j] += more[i][j];
            }
        }

        for (Index i=0; i<n; ++i)
            for (Index k=0; k<l; k++)
                column[i][k] /= 2;
    } else {
        b = n > POW ? n - POW : 0;
        auto c = n-b;
        for (Index k=0; k<l; k++) {
            Index gray = k ^ k/2;
            for (Index j=0; j<c; ++j)
                if (gray & 1 << j)
                    for (Index i=0; i<n; ++i)
                        column[i][k] -= input[(b+j)*n+i];
        }

        for (Index k=1; k<l; k+=2)
            column[0][k] = -column[0][k];

        for (Index i=0; i<b; ++i, bit <<= 1) {
            if (old_gray & bit) {
                bits = bits ^ 1;
                for (Index j=0; j<ww; ++j)
                    column[j] -= more[i][j];
            }
        }
    }

    if (DEBUG) {
        for (Index i=0; i<ww; ++i) {
            cout << "Column[" << i << "]=";
            for (Index j=0; j<ELEMS; ++j) cout << " " << column[i][j];
            cout << "\n";
        }
    }

    --more;
    old_gray = (from ^ from/2) | UINT64_C(1) << b;
    Value total = 0;
    SumN accu[WIDTH];
    for (auto p=from; p<to; ++p) {
        uint64_t new_gray = p ^ p/2;
        uint64_t bit = old_gray ^ new_gray;
        Index i = __builtin_ffsl(bit);
        auto diff = more[i];
        auto c = column;
        if (new_gray > old_gray) {
            // Phase 1 add/multiply.
            // Uses floats until just before loss of precision
            for (Index i=0; i<WIDTH; ++i) accu[i] = *c++ -= *diff++;

            for (Index j=1; j < nn; ++j)
                for (Index i=0; i<WIDTH; ++i) accu[i] *= *c++ -= *diff++;
        } else {
            // Phase 1 add/multiply.
            // Uses floats until just before loss of precision
            for (Index i=0; i<WIDTH; ++i) accu[i] = *c++ += *diff++;

            for (Index j=1; j < nn; ++j)
                for (Index i=0; i<WIDTH; ++i) accu[i] *= *c++ += *diff++;
        }

        if (DEBUG) {
            cout << "p=" << p << "\n";
            for (Index i=0; i<ww; ++i) {
                cout << "Column[" << i << "]=";
                for (Index j=0; j<ELEMS; ++j) cout << " " << column[i][j];
                cout << "\n";
            }
        }

        // Convert floats to int32_t
        ProdN prod32[WIDTH] __attribute__((aligned (32)));
        for (Index i=0; i<WIDTH; ++i)
            // Unfortunately gcc doesn't recognize the static_cast<int32_t>
            // as a vector pattern, so force it with an intrinsic
#ifdef __AVX__
            //prod32[i] = static_cast<ProdN>(accu[i]);
            reinterpret_cast<__m256i&>(prod32[i]) = _mm256_cvttps_epi32(accu[i]);
#else   // __AVX__
            for (Index j=0; j<ELEMS; ++j)
                prod32[i][j] = static_cast<int32_t>(accu[i][j]);
#endif  // __AVX__

        // Phase 2 multiply. Uses int64_t until just before overflow
        int64_t prod64[3][ELEMS];
        for (Index i=0; i<3; ++i) {
            for (Index j=0; j<ELEMS; ++j)
                prod64[i][j] = static_cast<int64_t>(prod32[i][j]) * prod32[i+3][j] * prod32[i+6][j];
        }
        // Phase 3 multiply. Collect into __int128. For large matrices this will
        // actually overflow but that's ok as long as all 128 low bits are
        // correct. Terms will cancel and the final sum can fit into 128 bits
        // (This will start to fail at n=35 for the all 1 matrix)
        // Strictly speaking this needs the -fwrapv gcc option
        for (Index j=0; j<ELEMS; ++j) {
            auto value = static_cast<Value>(prod64[0][j]) * prod64[1][j] * prod64[2][j];
            if (DEBUG) cout << "value[" << j << "]=" << static_cast<double>(value) << "\n";
            total += value;
        }
        total = -total;

        old_gray = new_gray;
    }

    return bits ? Number{-total} : Number{total};
}

// Prepare datastructures, Assign work to threads
Number permanent(Index n) {
    Index nn = (n+WIDTH-1)/WIDTH;
    Index ww = nn*WIDTH;

    Index rows  = n > (POW+glynn) ? n-POW-glynn : 0;
    auto data = alloc<SumN>(ww*(rows+1));
    auto pointers = alloc<SumN *>(rows+1);
    auto more = &pointers[0];
    for (Index i=0; i<rows; ++i)
        more[i] = &data[ww*i];
    more[rows] = &data[ww*rows];
    for (Index j=0; j<ww; ++j)
        for (Index i=0; i<ELEMS; ++i)
            more[rows][j][i] = 0;

    Index loops = n >= POW+glynn ? ELEMS : 1 << (n-glynn);
    auto a = &input[0];
    for (Index r=0; r<rows; ++r) {
        for (Index j=0; j<n; ++j) {
            for (Index i=0; i<loops; ++i)
                more[r][j][i] = j == 0 && i %2 ? -*a : *a;
            for (Index i=loops; i<ELEMS; ++i)
                more[r][j][i] = 0;
            ++a;
        }
        for (Index j=n; j<ww; ++j)
            for (Index i=0; i<ELEMS; ++i)
                more[r][j][i] = 0;
    }

    if (DEBUG)
        for (Index r=0; r<=rows; ++r)
            for (Index j=0; j<ww; ++j) {
                cout << "more[" << r << "][" << j << "]=";
                for (Index i=0; i<ELEMS; ++i)
                    cout << " " << more[r][j][i];
                cout << "\n";
            }

    // Send work to threads...
    vector<future<Number>> results;
    for (auto i=1U; i < nr_threads; ++i)
        results.emplace_back(async(DEBUG ? launch::deferred: launch::async, permanent_part, n, i, more));
    // And collect results
    auto r = permanent_part(n, 0, more);
    for (auto& result: results)
        r += result.get();

    free(data);
    free(pointers);

    // For glynn we should double the result, but we will only do this during
    // the final print. This allows n=34 for an all 1 matrix to work
    // if (glynn) r *= 2;
    return r;
}

// Print 128 bit number
void Number::print(ostream& os, bool dbl) const {
    const UValue BILLION = 1000000000;

    UValue val;
    if (value < 0) {
        os << "-";
        val = -value;
    } else
        val = value;
    if (dbl) val *= 2;

    uint32_t output[5];
    for (int i=0; i<5; ++i) {
        output[i] = val % BILLION;
        val /= BILLION;
    }
    bool print = false;
    for (int i=4; i>=0; --i) {
        if (print) {
            os << setfill('0') << setw(9) << output[i];
        } else if (output[i] || i == 0) {
            print = true;
            os << output[i];
        }
    }
}

// Read matrix, check for sanity
void my_main() {
    Sum a;
    while (cin >> a)
        input.push_back(a);

    size_t n = sqrt(input.size());
    if (input.size() != n*n)
        throw(logic_error("Read " + to_string(input.size()) +
                          " elements which does not make a square matrix"));

    vector<double> columns_pos(n, 0);
    vector<double> columns_neg(n, 0);
    Sum *p = &input[0];
    for (size_t i=0; i<n; ++i)
        for (size_t j=0; j<n; ++j, ++p) {
            if (*p >= 0) columns_pos[j] += *p;
            else         columns_neg[j] -= *p;
        }
    std::array<double,WIDTH> prod;
    prod.fill(1);

    int32_t odd = 0;
    for (size_t j=0; j<n; ++j) {
        prod[j%WIDTH] *= max(columns_pos[j], columns_neg[j]);
        auto sum = static_cast<int32_t>(columns_pos[j] - columns_neg[j]);
        odd |= sum;
    }
    glynn = (odd & 1) ^ 1;
    for (Index i=0; i<WIDTH; ++i)
        // A float has an implicit 1. in front of the fraction so it can
        // represent 1 bit more than the mantissa size. And 1 << (mantissa+1)
        // itself is in fact representable
        if (prod[i] && log2(prod[i]) > FLOAT_MANTISSA+1)
            throw(range_error("Values in matrix are too large. A subproduct reaches " + to_string(prod[i]) + " which doesn't fit in a float without loss of precision"));

    for (Index i=0; i<3; ++i) {
        auto prod3 = prod[i] * prod[i+3] * prod[i+6];
        if (log2(prod3) >= CHAR_BIT*sizeof(int64_t)-1)
            throw(range_error("Values in matrix are too large. A subproduct reaches " + to_string(prod3) + " which doesn't fit in an int64"));
    }

    nr_threads = pow(2, ceil(log2(static_cast<float>(nr_threads))));
    uint64_t loops = UINT64_C(1) << n;
    if (glynn) loops /= 2;
    if (nr_threads * ELEMS > loops)
        nr_threads = max(loops / ELEMS, UINT64_C(1));
    // if (DEBUG) nr_threads = 1;

    cout << n << " x " << n << " matrix, method " << (glynn ? "Glynn" : "Ryser") << ", " << nr_threads << " threads" << endl;

    // Go for the actual calculation
    auto start = chrono::steady_clock::now();
    auto perm = permanent(n);
    auto end = chrono::steady_clock::now();
    auto elapsed = chrono::duration_cast<ms>(end-start).count();

    cout << "Permanent=";
    perm.print(cout, glynn);
    cout << " (" << elapsed / 1000. << " s)" << endl;
}

// Wrapper to print any exceptions
int main() {
    try {
        my_main();
    } catch(exception& e) {
        cerr << "Error: " << e.what() << endl;
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

পতাকা: FPU vme ডি PSE টিএসসি MSR PAE MCE cx8 APIC সেপ্টেম্বর mtrr pge MCA cmov চাপড়ান pse36 clflush MMX fxsr SSE sse2 এইচটি প্রাপ্ত syscall Nx mmxext fxsr_opt pdpe1gb rdtscp LM constant_tsc rep_good nopl nonstop_tsc extd_apicid aperfmperf pni pclmulqdq নিরীক্ষণ ssse3 FMA cx16 sse4_1 sse4_2 popcnt AES xsave AVX f16c lahf_lm cmp_legacy svm extapic cr8_legacy এবিএম sse4a misalignsse 3dnowprefetch osvw আইবিএস xop skinit wdt lwp fma4 Tce nodeid_msr TBM topoext perfctr_core perfctr_nb সিপিবির hw_pstate vmmcall bmi1 arat NPT lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold

আপনার কোডটি চালানোর জন্য আমি এখনও আমার পরীক্ষার জোতাটি ডিবাগ করছি তবে এটি খুব দ্রুত দেখাচ্ছে, ধন্যবাদ! আমি ভাবছিলাম যে বড় আকারের আকারের কারণে কোনও গতির সমস্যা হতে পারে (যেমন আপনি পরামর্শ দিয়েছেন)। আমি তার আগ্রহের ক্ষেত্রে accu.org/index.php/articles/1849 দেখেছি ।

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

@ ল্যাম্বিক আমি রাইজারের সূত্রে স্যুইচ করেছি যেহেতু অন্যটি দিয়ে আমাকে আবার স্কেল করা দরকার 2 << (n-1)যার অর্থ আমার ইন্ট 128 জঞ্জালটি সেই বিন্দুর অনেক আগেই উপচে পড়েছিল।
টন হসপেল

1
@ ললেবিক হ্যাঁ :-)
টন হসপেল

7

C99, n ≈ 33 (35 সেকেন্ড)

#include <stdint.h>
#include <stdio.h>

#define CHUNK_SIZE 12
#define NUM_THREADS 8

#define popcnt __builtin_popcountll
#define BILLION (1000 * 1000 * 1000)
#define UPDATE_ROW_PPROD() \
    update_row_pprod(row_pprod, row, rows, row_sums, mask, mask_popcnt)

typedef __int128 int128_t;

static inline int64_t update_row_pprod
(
    int64_t* row_pprod, int64_t row, int64_t* rows,
    int64_t* row_sums, int64_t mask, int64_t mask_popcnt
)
{
    int64_t temp = 2 * popcnt(rows[row] & mask) - mask_popcnt;

    row_pprod[0] *= temp;
    temp -= 1;
    row_pprod[1] *= temp;
    temp -= row_sums[row];
    row_pprod[2] *= temp;
    temp += 1;
    row_pprod[3] *= temp;

    return row + 1;
}

int main(int argc, char* argv[])
{
    int64_t size = argc - 1, rows[argc - 1];
    int64_t row_sums[argc - 1];
    int128_t permanent = 0, sign = size & 1 ? -1 : 1;

    if (argc == 2)
    {
        printf("%d\n", argv[1][0] == '-' ? -1 : 1);
        return 0;
    }

    for (int64_t row = 0; row < size; row++)
    {
        char positive = argv[row + 1][0] == '+' ? '-' : '+';

        sign *= ',' - positive;
        rows[row] = row_sums[row] = 0;

        for (char* p = &argv[row + 1][1]; *p; p++)
        {
            rows[row] <<= 1;
            rows[row] |= *p == positive;
            row_sums[row] += *p == positive;
        }

        row_sums[row] = 2 * row_sums[row] - size;
    }

    #pragma omp parallel for reduction(+:permanent) num_threads(NUM_THREADS)
    for (int64_t mask = 1; mask < 1LL << (size - 1); mask += 2)
    {
        int64_t mask_popcnt = popcnt(mask);
        int64_t row = 0;
        int128_t row_prod = 1 - 2 * (mask_popcnt & 1);
        int128_t row_prod_high = -row_prod;
        int128_t row_prod_inv = row_prod;
        int128_t row_prod_inv_high = -row_prod;

        for (int64_t chunk = 0; chunk < size / CHUNK_SIZE; chunk++)
        {
            int64_t row_pprod[4] = {1, 1, 1, 1};

            for (int64_t i = 0; i < CHUNK_SIZE; i++)
                row = UPDATE_ROW_PPROD();

            row_prod *= row_pprod[0], row_prod_high *= row_pprod[1];
            row_prod_inv *= row_pprod[3], row_prod_inv_high *= row_pprod[2];
        }

        int64_t row_pprod[4] = {1, 1, 1, 1};

        while (row < size)
            row = UPDATE_ROW_PPROD();

        row_prod *= row_pprod[0], row_prod_high *= row_pprod[1];
        row_prod_inv *= row_pprod[3], row_prod_inv_high *= row_pprod[2];
        permanent += row_prod + row_prod_high + row_prod_inv + row_prod_inv_high;
    }

    permanent *= sign;

    if (permanent < 0)
        printf("-"), permanent *= -1;

    int32_t output[5], print = 0;

    output[0] = permanent % BILLION, permanent /= BILLION;
    output[1] = permanent % BILLION, permanent /= BILLION;
    output[2] = permanent % BILLION, permanent /= BILLION;
    output[3] = permanent % BILLION, permanent /= BILLION;
    output[4] = permanent % BILLION;

    if (output[4])
        printf("%u", output[4]), print = 1;
    if (print)
        printf("%09u", output[3]);
    else if (output[3])
        printf("%u", output[3]), print = 1;
    if (print)
        printf("%09u", output[2]);
    else if (output[2])
        printf("%u", output[2]), print = 1;
    if (print)
        printf("%09u", output[1]);
    else if (output[1])
        printf("%u", output[1]), print = 1;
    if (print)
        printf("%09u\n", output[0]);
    else
        printf("%u\n", output[0]);
}

ইনপুট বর্তমানে কিছুটা জটিল; এটি কমান্ড লাইন আর্গুমেন্ট হিসাবে সারিগুলির সাথে নেওয়া হয়, যেখানে প্রতিটি এন্ট্রি তার চিহ্ন দ্বারা উপস্থাপিত হয়, যেমন, + একটি 1 এবং - ই -1 নির্দেশ করে ।

টেস্ট রান

$ gcc -Wall -std=c99 -march=native -Ofast -fopenmp -fwrapv -o permanent permanent.c
$ ./permanent +--+ ---+ -+-+ +--+
-4
$ ./permanent ---- -+-- +--- +-+-
0
$ ./permanent +-+----- --++-++- +----+++ ---+-+++ +--++++- -+-+-++- +-+-+-+- --+-++++
192
$ ./permanent +-+--+++----++++-++- +-+++++-+--+++--+++- --+++----+-+++---+-- ---++-++++++------+- -+++-+++---+-+-+++++ +-++--+-++++-++-+--- +--+---+-++++---+++- +--+-++-+++-+-+++-++ +-----+++-----++-++- --+-+-++-+-++++++-++ -------+----++++---- ++---++--+-++-++++++ -++-----++++-----+-+ ++---+-+----+-++-+-+ +++++---+++-+-+++-++ +--+----+--++-+----- -+++-++--+++--++--++ ++--++-++-+++-++-+-+ +++---+--++---+----+ -+++-------++-++-+--
1021509632
$ time ./permanent +++++++++++++++++++++++++++++++{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}     # 31
8222838654177922817725562880000000

real    0m8.365s
user    1m6.504s
sys     0m0.000s
$ time ./permanent ++++++++++++++++++++++++++++++++{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}   # 32
263130836933693530167218012160000000

real    0m17.013s
user    2m15.226s
sys     0m0.001s
$ time ./permanent +++++++++++++++++++++++++++++++++{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,} # 33
8683317618811886495518194401280000000

real    0m34.592s
user    4m35.354s
sys     0m0.001s

উন্নতির জন্য আপনার কি কোনও ধারণা আছে?
xnor

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

@ ডেনিস লুপটি তালিকাভুক্তকরণ সম্পর্কে, উপরের সারিকে সমস্ত +1 করা একটি ছোট্ট সম্ভাব্য অপ্টিমাইজেশন।
xnor

@xnor হ্যাঁ, আমি চেষ্টা সময়ে যে, কিন্তু তারপর পরিবর্তন ফিরিয়ে আনা অন্য কিছু (যা কাজ করা হয়নি চেষ্টা এ সব )। বোতলের পূর্ণসংখ্যা গুণ (যা 64 বিট জন্য ধীর এবং মনে করা হয় সত্যিই 128 জন্য ধীর), যে কারণে আমি আশা করি SSE একটু সাহায্য করবে।
ডেনিস

1
@ ডেনিস আমি দেখতে পাচ্ছি সীমা সম্পর্কে, একটি অপ-সুস্পষ্ট বাউন্ডার অপারেটরের আদর্শ | পার (এম) | <= | এম | terms n এর নিরিখে। দেখুন arxiv.org/pdf/1606.07474v1.pdf
xnor

5

পাইথন 2, n ≈ 28

from operator import mul

def fast_glynn_perm(M):
    row_comb = [sum(c) for c in zip(*M)]
    n=len(M)

    total = 0
    old_grey = 0 
    sign = +1

    binary_power_dict = {2**i:i for i in range(n)}
    num_loops = 2**(n-1)

    for bin_index in xrange(1, num_loops + 1):  
        total += sign * reduce(mul, row_comb)

        new_grey = bin_index^(bin_index/2)
        grey_diff = old_grey ^ new_grey
        grey_diff_index = binary_power_dict[grey_diff]

        new_vector = M[grey_diff_index]
        direction = 2 * cmp(old_grey,new_grey)      

        for i in range(n):
            row_comb[i] += new_vector[i] * direction

        sign = -sign
        old_grey = new_grey

    return total/num_loops

আপডেটের জন্য গ্রে কোড সহ গ্লেন সূত্র ব্যবহার করে । আপ চালায় আমার মেশিনে এক মিনিটের মধ্যে। এটি অবশ্যই একটি দ্রুত ভাষায় এবং আরও ভাল ডেটা স্ট্রাকচার সহ আরও ভাল প্রয়োগ করতে পারে। এটি ব্যবহার করে না যে ম্যাট্রিক্সটি। 1-এর মূল্যবান।n=23

একটি রাইসার সূত্র বাস্তবায়ন খুব সমান, 0 1-ভেক্টরের পরিবর্তে সমস্ত সহগের 0/1 ভেক্টরগুলিকে সংযুক্ত করে। গ্লিনের সূত্রটি প্রায় দ্বিগুণ সময় নেয় কারণ এ জাতীয় সমস্ত ^ over n ভেক্টর যুক্ত করে, অন্যদিকে গ্লেনের অর্ধেকটি কেবলমাত্র যারা শুরু করে তাদের প্রতিসাম্য ব্যবহার করে +1

from operator import mul

def fast_ryser_perm(M):
    n=len(M)
    row_comb = [0] * n

    total = 0
    old_grey = 0 
    sign = +1

    binary_power_dict = {2**i:i for i in range(n)}
    num_loops = 2**n

    for bin_index in range(1, num_loops) + [0]: 
        total += sign * reduce(mul, row_comb)

        new_grey = bin_index^(bin_index/2)
        grey_diff = old_grey ^ new_grey
        grey_diff_index = binary_power_dict[grey_diff]

        new_vector = M[grey_diff_index]
        direction = cmp(old_grey, new_grey)

        for i in range(n):
            row_comb[i] += new_vector[i] * direction

        sign = -sign
        old_grey = new_grey

    return total * (-1)**n

অসাধারণ. আপনি পরীক্ষা করার জন্য পাইপী পেয়েছেন?

@ ল্যাম্বিক না, আমার খুব বেশি ইনস্টল নেই।
xnor

আমি এটি পরীক্ষা করার সময় পাইপাই ব্যবহার করব। অন্যান্য দ্রুত সূত্রটি কীভাবে কার্যকর করা যায় তা আপনি দেখতে পাচ্ছেন? আমি এটি বিভ্রান্তিকর মনে।

@ ল্যাম্বিক অন্যান্য দ্রুত সূত্রটি কী?
xnor

1
রেফারেন্স হিসাবে, এটি দিয়ে আমার মেশিনে 4466 সেকেন্ডের মধ্যে pypyসহজেই গণনা করতে সক্ষম হয়েছিল n=28। সামান্য দ্রুত না হলে লেম্বিকের সিস্টেমটি আমার কাছে গতির সাথে মোটামুটি তুলনাযোগ্য বলে মনে হচ্ছে।
কেড

4

মরিচা + এক্সট্রিম

ধূসর কোড প্রয়োগের সাথে সোজা এই রাইজারটি আমার ল্যাপটপে n = 31 চালাতে প্রায় 65 90 সেকেন্ড সময় নেয় । আমি ভাবছি আপনার মেশিনটি 60 এর চেয়ে কম বয়সে ভালভাবে আসবে। আমি এক্সট্রিম ব্যবহার করছি 1.1.1 এর জন্য i128

আমি কখনই মরিচা ব্যবহার করিনি এবং আমি কী করছি সে সম্পর্কে কোনও ধারণা নেই। যা কিছুই করা ছাড়া অন্য কোনও সংকলক বিকল্প cargo build --releaseনেই। মন্তব্য / পরামর্শ / অপ্টিমাইজেশান প্রশংসা করা হয়।

ডিনিসের প্রোগ্রামের অনুরোধ অনুরূপ।

use std::env;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc;

extern crate extprim;
use extprim::i128::i128;

static THREADS : i64 = 8; // keep this a power of 2.

fn main() {
  // Read command line args for the matrix, specified like
  // "++- --- -+-" for [[1, 1, -1], [-1, -1, -1], [-1, 1, -1]].
  let mut args = env::args();
  args.next();

  let mat : Arc<Vec<Vec<i64>>> = Arc::new(args.map( |ss|
    ss.trim().bytes().map( |cc| if cc == b'+' {1} else {-1}).collect()
  ).collect());

  // Figure how many iterations each thread has to do.
  let size = 2i64.pow(mat.len() as u32);
  let slice_size = size / THREADS; // Assumes divisibility.

  let mut accumulator : i128;
  if slice_size >= 4 { // permanent() requires 4 divides slice_size
    let (tx, rx) = mpsc::channel();

    // Launch threads.
    for ii in 0..THREADS {
      let mat = mat.clone();
      let tx = tx.clone();
      thread::spawn(move ||
        tx.send(permanent(&mat, ii * slice_size, (ii+1) * slice_size))
      );
    }

    // Accumulate results.
    accumulator = extprim::i128::ZERO;
    for _ in 0..THREADS {
      accumulator += rx.recv().unwrap();
    }
  }
  else { // Small matrix, don't bother threading.
    accumulator = permanent(&mat, 0, size);
  }
  println!("{}", accumulator);
}

fn permanent(mat: &Vec<Vec<i64>>, start: i64, end: i64) -> i128 {
  let size = mat.len();
  let sentinel = std::i64::MAX / size as i64;

  let mut bits : Vec<bool> = Vec::with_capacity(size);
  let mut sums : Vec<i64> = Vec::with_capacity(size);

  // Initialize gray code bits.
  let gray_number = start ^ (start / 2);

  for row in 0..size {
    bits.push((gray_number >> row) % 2 == 1);
    sums.push(0);
  }

  // Initialize column sums
  for row in 0..size {
    if bits[row] {
      for column in 0..size {
        sums[column] += mat[row][column];
      }
    }
  }

  // Do first two iterations with initial sums
  let mut total = product(&sums, sentinel);
  for column in 0..size {
    sums[column] += mat[0][column];
  }
  bits[0] = true;

  total -= product(&sums, sentinel);

  // Do rest of iterations updating gray code bits incrementally
  let mut gray_bit : usize;
  let mut idx = start + 2;
  while idx < end {
    gray_bit = idx.trailing_zeros() as usize;

    if bits[gray_bit] {
      for column in 0..size {
        sums[column] -= mat[gray_bit][column];
      }
      bits[gray_bit] = false;
    }
    else {
      for column in 0..size {
        sums[column] += mat[gray_bit][column];
      }
      bits[gray_bit] = true;
    }

    total += product(&sums, sentinel);

    if bits[0] {
      for column in 0..size {
        sums[column] -= mat[0][column];
      }
      bits[0] = false;
    }
    else {
      for column in 0..size {
        sums[column] += mat[0][column];
      }
      bits[0] = true;
    }

    total -= product(&sums, sentinel);
    idx += 2;
  }
  return if size % 2 == 0 {total} else {-total};
}

#[inline]
fn product(sums : &Vec<i64>, sentinel : i64) -> i128 {
  let mut ret : Option<i128> = None;
  let mut tally = sums[0];
  for ii in 1..sums.len() {
    if tally.abs() >= sentinel {
      ret = Some(ret.map_or(i128::new(tally), |n| n * i128::new(tally)));
      tally = sums[ii];
    }
    else {
      tally *= sums[ii];
    }
  }
  if ret.is_none() {
    return i128::new(tally);
  }
  return ret.unwrap() * i128::new(tally);
}

এক্সট্রিম ইনস্টল এবং কোডটি সংকলনের জন্য আপনি কি অনুলিপি এবং পেস্টেবল কমান্ড লাইন দিতে পারেন?

আউটপুটটি "i128! (- 2)" বলে মনে হচ্ছে যেখানে -2 সঠিক উত্তর। এটি কি প্রত্যাশিত এবং আপনি কেবল স্থায়ী দয়া করে আউটপুটে পরিবর্তন করতে পারবেন?

1
@ ল্যাম্বিক: আউটপুট এখনই ঠিক করা উচিত। দেখে মনে হচ্ছে আপনি সংকলনটি বের করেছেন, তবে আমি এটিকে গিতে ফেলে দিয়েছি যাতে আপনি git clone https://gitlab.com/ezrast/permanent.git; cd permanent; cargo build --releaseআমার মতো একই সেটআপ স্থাপনের বিষয়ে নিশ্চিত হতে চাইলে আপনি এটি করতে পারেন। কার্গো নির্ভরতা পরিচালনা করবে। বাইনারি ভিতরে যায় target/release
এজাস্ট

দুর্ভাগ্যক্রমে এটি n = 29 এর ভুল উত্তর দেয় b bpaste.net/show/99d6e826d968

1
@ ল্যাম্বিক গাহ, দুঃখিত, মধ্যবর্তী মানগুলি আমি ভেবেছিলাম তার আগে প্রবাহিত হয়েছিল। এটি ঠিক করা হয়েছে, যদিও প্রোগ্রামটি এখন অনেক ধীর।
এস্ট্রাস্ট

4

হাস্কেল, এন = 31 (54 সে)

@ অং দ্বারা প্রচুর অমূল্য অবদান সহ: ব্যবহার করুন Vector, শর্ট সার্কিট পণ্য ব্যবহার করুন , বিজোড় এন দেখুন।

import Control.Parallel.Strategies
import qualified Data.Vector.Unboxed as V
import Data.Int

type Row = V.Vector Int8

x :: Row -> [Row] -> Integer -> Int -> Integer
x p (v:vs) m c = let c' = c - 1
                     r = if c>0 then parTuple2 rseq rseq else r0
                     (a,b) = ( x p                  vs m    c' ,
                               x (V.zipWith(-) p v) vs (-m) c' )
                             `using` r
                 in a+b
x p _      m _ = prod m p

prod :: Integer -> Row -> Integer
prod m p = if 0 `V.elem` p then 0 
                           else V.foldl' (\a b->a*fromIntegral b) m p

p, pt :: [Row] -> Integer
p (v:vs) = x (foldl (V.zipWith (+)) v vs) (map (V.map (2*)) vs) 1 11
           `div` 2^(length vs)
p [] = 1 -- handle 0x0 matrices too  :-)

pt (v:vs) | even (length vs) = p ((V.map (2*) v) : vs ) `div` 2
pt mat                       = p mat

main = getContents >>= print . pt . map V.fromList . read

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

pস্থায়ী গণনা। একে বলা হয় যার মাধ্যমে ptম্যাট্রিক্স এমনভাবে রূপান্তরিত হয় যা সর্বদা বৈধ, তবে আমরা এখানে যে ম্যাট্রিকগুলি পাই তার জন্য বিশেষভাবে কার্যকর।

সঙ্গে সংকলন ghc -O2 -threaded -fllvm -feager-blackholing -o <name> <name>.hs। Parallelisation সঙ্গে চালাতে, দিতে এটা ভালো পরামিতি রানটাইম: ./<name> +RTS -N। ইনপুটটি স্ট্যান্ডিন থেকে নেস্টেড কমা দ্বারা পৃথক তালিকার সাথে বন্ধনীতে [[1,2],[3,4]]শেষ উদাহরণের মতো (নতুন লাইনে সর্বত্র অনুমোদিত)।


1
আমি প্লাগ ইন করে 20-25% গতি উন্নতি করতে সক্ষম হয়েছি Data.Vector। পরিবর্তনগুলি পরিবর্তিত ফাংশন ধরনের বিভাগকে: import qualified Data.Vector as V, x (V.zipWith(-) p v) vs (-m) c' ), p (v:vs) = x (foldl (V.zipWith (+)) v vs) (map (V.map (2*)) vs) 1 11,main = getContents >>= print . p . map V.fromList . read
Angs

1
@ অনেক ধন্যবাদ! আমি আরও ভাল উপযোগী ডেটাটাইপগুলি সন্ধান করার মতো মনে করি না। এটি আশ্চর্যজনক যে কীভাবে ছোট জিনিসগুলি পরিবর্তন করতে হবে (এটিও ব্যবহার করতে হয়েছিল V.product)। এটি কেবল আমাকে 10% দিয়েছে। কোডটি পরিবর্তন করা হয়েছে যাতে ভেক্টরগুলিতে কেবল Intএস। এগুলি ঠিক আছে কারণ এগুলি কেবল যুক্ত করা হয়েছে, বড় সংখ্যাগুলি গুণ থেকে আসে। তারপরে এটি ছিল 20%। আমি পুরানো কোড দিয়ে একই পরিবর্তন চেষ্টা করেছিলাম, কিন্তু সেই সময় এটি এটিকে কমিয়ে দেয়। আমি আবার চেষ্টা করেছি কারণ এটি আনবক্সযুক্ত ভেক্টর ব্যবহার করতে দেয় যা অনেক সাহায্য করেছিল!
খ্রিস্টান সিভর্স ২

1
@ খ্রিস্টান-সিভারস গ্ল্যাব আমি সাহায্য করতে পারি। এখানে আমি খুঁজে পেয়েছি আরও একটি মজাদার ভাগ্য-ভিত্তিক অপ্টিমাইজেশন: x p _ m _ = m * (sum $ V.foldM' (\a b -> if b==0 then Nothing else Just $ a*fromIntegral b) 1 p)- একাকী ভাঁজ হিসাবে পণ্য যেখানে 0 একটি বিশেষ ক্ষেত্রে। মনে হয় না অনেক বেশি উপকারী হবে।
অ্যাঙ্গস

1
@ গ্রেট! উদাহরণস্বরূপ ডিবিয়ান স্থিতিশীল থেকে জিএইচসি-র জন্য Transversableআমি এটি এমন একটি ফর্মের পরিবর্তিত করেছি যার দরকার নেই (আমি দেখছি আপনার খাবার productখাওয়ার বদল করা কোনও ভুল ছিল না ...)। এটি ইনপুটটির ফর্মটি ব্যবহার করছে তবে এটি দুর্দান্ত বলে মনে হচ্ছে: আমরা এর উপর নির্ভর করছি না, কেবল এটির জন্য অনুকূলিত করছি। সময়কে অনেক বেশি উত্তেজনাপূর্ণ করে তোলে: আমার এলোমেলো 30x30 ম্যাট্রিক্স 29x29 এর চেয়ে কিছুটা দ্রুত, তবে 31x31 4x সময় নেয়। - এই অনলাইনটি আমার পক্ষে কাজ করে না বলে মনে হচ্ছে। এএফএআইকে এটি পুনরাবৃত্তির কাজগুলির জন্য উপেক্ষা করা হয়।
ক্রিশ্চান সিভর্স

1
@ খ্রিস্টান-সিভার্স হ্যাঁ, আমি সে সম্পর্কে কিছু বলতে যাচ্ছিলাম product তবে ভুলে গিয়েছিলাম। মনে হচ্ছে কেবল দৈর্ঘ্যের শূন্য রয়েছে p, সুতরাং বিজোড় দৈর্ঘ্যের জন্য আমাদের উভয় বিশ্বের সেরা পেতে সংক্ষিপ্ত সার্কিটের পরিবর্তে নিয়মিত পণ্য ব্যবহার করা উচিত।
অ্যাঙ্গস

3

গণিত, n ≈ 20

p[m_] := Last[Fold[Take[ListConvolve[##, {1, -1}, 0], 2^Length[m]]&,
  Table[If[IntegerQ[Log2[k]], m[[j, Log2[k] + 1]], 0], {j, n}, {k, 0, 2^Length[m] - 1}]]]

Timingকমান্ডটি ব্যবহার করে , একটি 20x20 ম্যাট্রিক্সের জন্য আমার সিস্টেমে প্রায় 48 সেকেন্ডের প্রয়োজন। এটি অন্যটির মতো ঠিক তেমন দক্ষ নয় কারণ এটি ম্যাট্রিক্সের প্রতিটি সারি থেকে পলিমোমিয়ালের পণ্যটির সহগ হিসাবে স্থায়ী হিসাবে পাওয়া যেতে পারে তার উপর নির্ভর করে। দক্ষ বহুভিত্তিক গুণটি সহগের তালিকা তৈরি করে এবং ব্যবহারের মাধ্যমে সমাবর্তন সম্পাদন করে সম্পাদিত হয় ListConvolve। এটির জন্য প্রায় O (2 n n 2 ) সময় ধরে ফিউচার ফুরিয়ার ট্রান্সফর্ম বা অনুরূপ ব্যবহারের জন্য ( n লগ এন ) সময় প্রয়োজন বলে সমঝোতা সমাপ্তি ঘটে ।


3

পাইথন 2, এন = 22 [রেফারেন্স]

গতকাল লেম্বিকের সাথে আমি এই 'রেফারেন্স' বাস্তবায়নটি ভাগ করেছি n=23, এটি আমার মেশিনে কয়েক সেকেন্ডের মধ্যে এটিকে তৈরি করা মিস করে, আমার মেশিনে এটি প্রায় 52 সেকেন্ডের মধ্যে এটি করে। এই গতি অর্জন করতে আপনাকে পাইপাইয়ের মাধ্যমে এটি চালানো দরকার।

প্রথম ফাংশন স্থায়ী হিসাবে গণনা করতে পারে কীভাবে নির্ধারক গণনা করা যেতে পারে তার অনুরূপ, প্রতিটি সাবমেট্রিক্সের উপর দিয়ে যতক্ষণ না আপনি 2x2 রেখে যান যেখানে আপনি বেসিক নিয়মটি প্রয়োগ করতে পারেন। এটি অবিশ্বাস্যভাবে ধীর

দ্বিতীয় ফাংশনটি হ'ল রাইজার ফাংশন প্রয়োগকারী (উইকিপিডিয়ায় তালিকাভুক্ত দ্বিতীয় সমীকরণ)। সেটটি Sমূলত সংখ্যার পাওয়ারেট {1,...,n}( s_listকোডে পরিবর্তনশীল )।

from random import *
from time import time
from itertools import*

def perm(a): # naive method, recurses over submatrices, slow 
    if len(a) == 1:
        return a[0][0]
    elif len(a) == 2:
        return a[0][0]*a[1][1]+a[1][0]*a[0][1]
    else:
        tsum = 0
        for i in xrange(len(a)):
            transposed = [zip(*a)[j] for j in xrange(len(a)) if j != i]
            tsum += a[0][i] * perm(zip(*transposed)[1:])
        return tsum

def perm_ryser(a): # Ryser's formula, using matrix entries
    maxn = len(a)
    n_list = range(1,maxn+1)
    s_list = chain.from_iterable(combinations(n_list,i) for i in range(maxn+1))
    total = 0
    for st in s_list:
        stotal = (-1)**len(st)
        for i in xrange(maxn):
            stotal *= sum(a[i][j-1] for j in st)
        total += stotal
    return total*((-1)**maxn)


def genmatrix(d):
    mat = []
    for x in xrange(d):
        row = []
        for y in xrange(d):
            row.append([-1,1][randrange(0,2)])
        mat.append(row)
    return mat

def main():
    for i in xrange(1,24):
        k = genmatrix(i)
        print 'Matrix: (%dx%d)'%(i,i)
        print '\n'.join('['+', '.join(`j`.rjust(2) for j in a)+']' for a in k)
        print 'Permanent:',
        t = time()
        p = perm_ryser(k)
        print p,'(took',time()-t,'seconds)'

if __name__ == '__main__':
    main()

আমি মনে করি আপনার বিবরণটি "নির্ধারণকারী গণনা করা হবে তার অনুরূপ" পুনরায় লিখতে হবে। মনে হচ্ছে না নির্ধারণকারী জন্য পদ্ধতি permanents জন্য ধীর, কিন্তু নির্ধারণকারী এক ধীর পদ্ধতি permanents জন্য একভাবে কাজ করে (এবং ধীরে ধীরে হিসাবে)।
খ্রিস্টান সিভর্স

1
@ ক্রিশ্চিয়ন্সআইভার্স ভাল কথা, আমি এটি পরিবর্তন করেছি।
কেদে

2

RPython 5.4.1, n ≈ 32 (37 সেকেন্ড)

from rpython.rlib.rtime import time
from rpython.rlib.rarithmetic import r_int, r_uint
from rpython.rlib.rrandom import Random
from rpython.rlib.rposix import pipe, close, read, write, fork, waitpid
from rpython.rlib.rbigint import rbigint

from math import log, ceil
from struct import pack

bitsize = len(pack('l', 1)) * 8 - 1

bitcounts = bytearray([0])
for i in range(16):
  b = bytearray([j+1 for j in bitcounts])
  bitcounts += b


def bitcount(n):
  bits = 0
  while n:
    bits += bitcounts[n & 65535]
    n >>= 16
  return bits


def main(argv):
  if len(argv) < 2:
    write(2, 'Usage: %s NUM_THREADS [N]'%argv[0])
    return 1
  threads = int(argv[1])

  if len(argv) > 2:
    n = int(argv[2])
    rnd = Random(r_uint(time()*1000))
    m = []
    for i in range(n):
      row = []
      for j in range(n):
        row.append(1 - r_int(rnd.genrand32() & 2))
      m.append(row)
  else:
    m = []
    strm = ""
    while True:
      buf = read(0, 4096)
      if len(buf) == 0:
        break
      strm += buf
    rows = strm.split("\n")
    for row in rows:
      r = []
      for val in row.split(' '):
        r.append(int(val))
      m.append(r)
    n = len(m)

  a = []
  for row in m:
    val = 0
    for v in row:
      val = (val << 1) | -(v >> 1)
    a.append(val)

  batches = int(ceil(n * log(n) / (bitsize * log(2))))

  pids = []
  handles = []
  total = rbigint.fromint(0)
  for i in range(threads):
    r, w = pipe()
    pid = fork()
    if pid:
      close(w)
      pids.append(pid)
      handles.append(r)
    else:
      close(r)
      total = run(n, a, i, threads, batches)
      write(w, total.str())
      close(w)
      return 0

  for pid in pids:
    waitpid(pid, 0)

  for handle in handles:
    strval = read(handle, 256)
    total = total.add(rbigint.fromdecimalstr(strval))
    close(handle)

  print total.rshift(n-1).str()

  return 0


def run(n, a, mynum, threads, batches):
  start = (1 << n-1) * mynum / threads
  end = (1 << n-1) * (mynum+1) / threads

  dtotal = rbigint.fromint(0)
  for delta in range(start, end):
    pdelta = rbigint.fromint(1 - ((bitcount(delta) & 1) << 1))
    for i in range(batches):
      pbatch = 1
      for j in range(i, n, batches):
        pbatch *= n - (bitcount(delta ^ a[j]) << 1)
      pdelta = pdelta.int_mul(pbatch)
    dtotal = dtotal.add(pdelta)

  return dtotal


def target(*args):
  return main

সংকলন করতে, অতি সাম্প্রতিক পাইপাই উত্সটি ডাউনলোড করুন এবং নিম্নলিখিতগুলি সম্পাদন করুন:

pypy /path/to/pypy-src/rpython/bin/rpython matrix-permanent.py

ফলস্বরূপ এক্সিকিউটেবলের matrix-permanent-cবর্তমান কার্যনির্বাহী ডিরেক্টরিতে নাম দেওয়া বা সিমেন্ট করা হবে ।

পিপিওয়াই 5.0 হিসাবে, আরপিথনের থ্রেডিং আদিমগুলি আগের তুলনায় অনেক কম আদিম। নতুনভাবে প্রসারিত থ্রেডগুলির জন্য জিআইএল প্রয়োজন, যা সমান্তরাল গণনার জন্য কম-বেশি অকেজো। আমি এর forkপরিবর্তে ব্যবহার করেছি , সুতরাং এটি উইন্ডোজে প্রত্যাশার মতো কাজ নাও করতে পারে, যদিও আমি ( unresolved external symbol _fork) সংকলন করতে ব্যর্থতা পরীক্ষা করেছি না

এক্সিকিউটেবল দুটি কমান্ড লাইনের পরামিতি গ্রহণ করে। প্রথমটি থ্রেডের সংখ্যা, দ্বিতীয় alচ্ছিক পরামিতি n। যদি এটি সরবরাহ করা হয় তবে একটি এলোমেলো ম্যাট্রিক্স উত্পন্ন হবে, অন্যথায় এটি স্টিডিনের কাছ থেকে পড়া হবে। প্রতিটি সারিটি অবশ্যই নতুন লাইনের দ্বারা পৃথক হওয়া উচিত (কোনও পেছনের নিউলাইন ছাড়াই) এবং প্রতিটি মান স্থান পৃথক করতে হবে। তৃতীয় উদাহরণ ইনপুট হিসাবে দেওয়া হবে:

1 -1 1 -1 -1 1 1 1 -1 -1 -1 -1 1 1 1 1 -1 1 1 -1
1 -1 1 1 1 1 1 -1 1 -1 -1 1 1 1 -1 -1 1 1 1 -1
-1 -1 1 1 1 -1 -1 -1 -1 1 -1 1 1 1 -1 -1 -1 1 -1 -1
-1 -1 -1 1 1 -1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 1 -1
-1 1 1 1 -1 1 1 1 -1 -1 -1 1 -1 1 -1 1 1 1 1 1
1 -1 1 1 -1 -1 1 -1 1 1 1 1 -1 1 1 -1 1 -1 -1 -1
1 -1 -1 1 -1 -1 -1 1 -1 1 1 1 1 -1 -1 -1 1 1 1 -1
1 -1 -1 1 -1 1 1 -1 1 1 1 -1 1 -1 1 1 1 -1 1 1
1 -1 -1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 1 1 -1 1 1 -1
-1 -1 1 -1 1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1 1 1
-1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1
1 1 -1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 1 1 1 1 1 1
-1 1 1 -1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 -1 1 -1 1
1 1 -1 -1 -1 1 -1 1 -1 -1 -1 -1 1 -1 1 1 -1 1 -1 1
1 1 1 1 1 -1 -1 -1 1 1 1 -1 1 -1 1 1 1 -1 1 1
1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 -1 1 -1 -1 -1 -1 -1
-1 1 1 1 -1 1 1 -1 -1 1 1 1 -1 -1 1 1 -1 -1 1 1
1 1 -1 -1 1 1 -1 1 1 -1 1 1 1 -1 1 1 -1 1 -1 1
1 1 1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 1 -1 -1 -1 -1 1
-1 1 1 1 -1 -1 -1 -1 -1 -1 -1 1 1 -1 1 1 -1 1 -1 -1

নমুনা ব্যবহার

$ time ./matrix-permanent-c 8 30
8395059644858368

real    0m8.582s
user    1m8.656s
sys     0m0.000s

পদ্ধতি

আমি বালসুব্রামিয়ান-বাক্স / ফ্র্যাঙ্কলিন-গ্লেন সূত্র ব্যবহার করেছি , ও (2 এন এন) এর রানটাইম জটিলতার সাথে । তবে ধূসর কোড ক্রমে ite এর পুনরাবৃত্তি না করে আমি পরিবর্তে একক জোড় অপারেশন (ম্যাপিং (1, -1) → (0, 1)) এর সাথে ভেক্টর-সারি গুণকে প্রতিস্থাপন করেছি। পপকাউন্টের দ্বিগুণ এন বিয়োগ করে ভেক্টর যোগফল একইভাবে একক ক্রিয়ায় পাওয়া যাবে।


দুর্ভাগ্যক্রমে কোডটি bpaste.net/

@ লেম্বিক আপডেট হয়েছে। কৌতূহলের বাইরে, আপনি কি আমাকে নীচের কোডের ফলাফল বলতে পারেন? bpaste.net/show/76ec65e1b533
primo

এটি "সত্য 18446744073709551615" দেয় আমি এখন কোডে আপনার খুব সুন্দর ফলাফলও যুক্ত করেছি।

@ ল্যাম্বিক ধন্যবাদ আমি ইতিমধ্যে lic৩-বিটকে ওভারফ্লো না করার জন্য গুণটি ভাগ করে নিয়েছি। ফলাফলটি কি 8 টি থ্রেড সহ নেওয়া হয়েছিল? 2 বা 4 একটি পার্থক্য আছে? যদি 25-তে 30 শেষ হয় তবে মনে হয় 31 এর এক মিনিটের মধ্যে হওয়া উচিত।
প্রিমো

-1

রেকেট 84 বাইট

নিম্নলিখিত সাধারণ ফাংশনটি ছোট ম্যাট্রিক্সের জন্য কাজ করে তবে বড় ম্যাট্রিক্সের জন্য আমার মেশিনে ঝুলছে:

(for/sum((p(permutations(range(length l)))))(for/product((k l)(c p))(list-ref k c)))

Ungolfed:

(define (f ll) 
  (for/sum ((p (permutations (range (length ll))))) 
    (for/product ((l ll)(c p)) 
      (list-ref l c))))

কোডটি সহজেই সারি এবং কলামগুলির অসম সংখ্যাগুলির জন্য সংশোধন করা যেতে পারে।

পরীক্ষামূলক:

(f '[[ 1 -1 -1  1]
     [-1 -1 -1  1]
     [-1  1 -1  1]
     [ 1 -1 -1  1]])

(f '[[ 1 -1  1 -1 -1 -1 -1 -1]
 [-1 -1  1  1 -1  1  1 -1]
 [ 1 -1 -1 -1 -1  1  1  1]
 [-1 -1 -1  1 -1  1  1  1]
 [ 1 -1 -1  1  1  1  1 -1]
 [-1  1 -1  1 -1  1  1 -1]
 [ 1 -1  1 -1  1 -1  1 -1]
 [-1 -1  1 -1  1  1  1  1]])

আউটপুট:

-4
192

আমি উপরে উল্লিখিত হিসাবে, এটি নিম্নলিখিত পরীক্ষার উপর স্তব্ধ:

(f '[[1 -1 1 -1 -1 1 1 1 -1 -1 -1 -1 1 1 1 1 -1 1 1 -1]
 [1 -1 1 1 1 1 1 -1 1 -1 -1 1 1 1 -1 -1 1 1 1 -1]
 [-1 -1 1 1 1 -1 -1 -1 -1 1 -1 1 1 1 -1 -1 -1 1 -1 -1]
 [-1 -1 -1 1 1 -1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 1 -1]
 [-1 1 1 1 -1 1 1 1 -1 -1 -1 1 -1 1 -1 1 1 1 1 1]
 [1 -1 1 1 -1 -1 1 -1 1 1 1 1 -1 1 1 -1 1 -1 -1 -1]
 [1 -1 -1 1 -1 -1 -1 1 -1 1 1 1 1 -1 -1 -1 1 1 1 -1]
 [1 -1 -1 1 -1 1 1 -1 1 1 1 -1 1 -1 1 1 1 -1 1 1]
 [1 -1 -1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 1 1 -1 1 1 -1]
 [-1 -1 1 -1 1 -1 1 1 -1 1 -1 1 1 1 1 1 1 -1 1 1]
 [-1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1]
 [1 1 -1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 1 1 1 1 1 1]
 [-1 1 1 -1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 -1 1 -1 1]
 [1 1 -1 -1 -1 1 -1 1 -1 -1 -1 -1 1 -1 1 1 -1 1 -1 1]
 [1 1 1 1 1 -1 -1 -1 1 1 1 -1 1 -1 1 1 1 -1 1 1]
 [1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 -1 1 -1 -1 -1 -1 -1]
 [-1 1 1 1 -1 1 1 -1 -1 1 1 1 -1 -1 1 1 -1 -1 1 1]
 [1 1 -1 -1 1 1 -1 1 1 -1 1 1 1 -1 1 1 -1 1 -1 1]
 [1 1 1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 1 -1 -1 -1 -1 1]
 [-1 1 1 1 -1 -1 -1 -1 -1 -1 -1 1 1 -1 1 1 -1 1 -1 -1]])

3
এই উত্তরটি এই প্রশ্নের গতি সংস্করণের চেয়ে কোডগল্ফ সংস্করণে আরও ভাল?
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.