হ্যাঙ্কলেবল ম্যাট্রিক্সের সংখ্যা গণনা করুন


12

পটভূমি

একটি বাইনারি হ্যাঙ্কেল ম্যাট্রিক্স একটি ম্যাট্রিক্স যা ধ্রুবক স্কিউ-ডায়াগোনাল (ধনাত্মক opালু ত্রিভুজ) কেবলমাত্র 0এস এবং 1এস সমন্বিত। যেমন একটি 5x5 বাইনারি হ্যান্কেল ম্যাট্রিক্স দেখতে দেখতে looks

a b c d e
b c d e f
c d e f g
d e f g h
e f g h i

যেখানে a, b, c, d, e, f, g, h, iহয় পারেন 0বা 1

আসুন একটি ম্যাট্রিক্স সংজ্ঞায়িত এম যেমন Hankelable যদি সারি এবং কলাম ক্রম একটি বিন্যাস হল এম যাতে এম একটি Hankel ম্যাট্রিক্স হয়। এর অর্থ সারিগুলির ক্রমে একটির অনুমতি এবং সম্ভবত কলামগুলিতে আলাদা আলাদা প্রয়োগ করা যেতে পারে।

চ্যালেঞ্জ

চ্যালেঞ্জটি হ'ল ম্যাট্রিকগুলি দ্বারা কতগুলি হানকেলেবল সম্ভব যতটা সম্ভব একটি বড় মূল্য গণনা করা ।nnn

আউটপুট

প্রতিটি পূর্ণসংখ্যা জন্য এন 1 ঊর্ধ্বমুখী, আউটপুট নম্বর থেকে Hankelable n দ্বারা nএন্ট্রি যা সঙ্গে ম্যাট্রিক্স 0বা 1

জন্য n = 1,2,3,4,5উত্তর হওয়া উচিত 2,12,230,12076,1446672। (এগুলি তৈরির জন্য কোডটির জন্য orlp ধন্যবাদ))

সময় সীমা

আমি আপনার কোডটি আমার মেশিনে চালাব এবং 1 মিনিটের পরে এটি বন্ধ করব। কোড যা সঠিক উত্তরগুলিকে এন বিজয়ের বৃহত্তম মান পর্যন্ত আউটপুট করে। সময় সীমা হ'ল n = 1সবচেয়ে বড় মানের থেকে শুরু করে nযার জন্য আপনি একটি উত্তর দেন everything

শনিবার 18 এপ্রিলের মধ্যে বিজয়ী সেরা উত্তর হবে।

টাইব্রেকার

বেশিরভাগ ক্ষেত্রে টাই করার ক্ষেত্রে nআমি আউটপুটগুলি দিতে n+1এবং এটি দ্রুততমটিতে জয়ী হতে কত সময় নেয় তা সময় নিয়ে যাব । যে ক্ষেত্রে তারা একই সময়ে চালিত হয় এক সেকেন্ড পর্যন্ত n+1, প্রথম জমা জিততে পারে।

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

আপনি যে কোনও ভাষা নিখরচায় উপলব্ধ সংকলক / দোভাষী / ইত্যাদি ব্যবহার করতে পারেন। লিনাক্স এবং যে কোনও লাইব্রেরির জন্য লিনাক্সের জন্য নিখরচায় উপলব্ধ।

আমার যন্ত্র

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

মন্তব্য

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

এখনও পর্যন্ত নেতৃস্থানীয় এন্ট্রি

  • n = 8 পিটার টেলর দ্বারা। জাভা
  • অর্প দ্বারা n = 5 পাইথন

4
আমি সত্যিই "হ্যাঙ্কেলেবল" শব্দটি উপভোগ করছি।
অ্যালেক্স এ।

3
জন্য n=6মোট 260357434। আমি মনে করি মেমরি প্রেসার সিপিইউ সময়ের চেয়ে বড় সমস্যা।
পিটার টেলর

এটি একটি দুর্দান্ত প্রশ্ন। আমি পুরোপুরি অস্থির-স্নিপড হয়েছি।
অ্যালেক্সান্ডার-ব্রেট

উত্তর:


7

জাভা (এন = 8)

import java.util.*;
import java.util.concurrent.*;

public class HankelCombinatorics {
    public static final int NUM_THREADS = 8;

    private static final int[] FACT = new int[13];
    static {
        FACT[0] = 1;
        for (int i = 1; i < FACT.length; i++) FACT[i] = i * FACT[i-1];
    }

    public static void main(String[] args) {
        long prevElapsed = 0, start = System.nanoTime();
        for (int i = 1; i < 12; i++) {
            long count = count(i), elapsed = System.nanoTime() - start;
            System.out.format("%d in %dms, total elapsed %dms\n", count, (elapsed - prevElapsed) / 1000000, elapsed / 1000000);
            prevElapsed = elapsed;
        }
    }

    @SuppressWarnings("unchecked")
    private static long count(int n) {
        int[][] perms = new int[FACT[n]][];
        genPermsInner(0, 0, new int[n], perms, 0);

        // We partition by canonical representation of the row sum multiset, discarding any with a density > 50%.
        Map<CanonicalMatrix, Map<CanonicalMatrix, Integer>> part = new HashMap<CanonicalMatrix, Map<CanonicalMatrix, Integer>>();
        for (int m = 0; m < 1 << (2*n-1); m++) {
            int density = 0;
            int[] key = new int[n];
            for (int i = 0; i < n; i++) {
                key[i] = Integer.bitCount((m >> i) & ((1 << n) - 1));
                density += key[i];
            }
            if (2 * density <= n * n) {
                CanonicalMatrix _key = new CanonicalMatrix(key);
                Map<CanonicalMatrix, Integer> map = part.get(_key);
                if (map == null) part.put(_key, map = new HashMap<CanonicalMatrix, Integer>());
                map.put(new CanonicalMatrix(m, perms[0]), m);
            }
        }

        List<Job> jobs = new ArrayList<Job>();
        ExecutorService pool = Executors.newFixedThreadPool(NUM_THREADS);

        for (Map.Entry<CanonicalMatrix, Map<CanonicalMatrix, Integer>> e : part.entrySet()) {
            Job job = new Job(n, perms, e.getKey().sum() << 1 == n * n ? 0 : 1, e.getValue());
            jobs.add(job);
            pool.execute(job);
        }

        pool.shutdown();
        try {
            pool.awaitTermination(1, TimeUnit.DAYS); // i.e. until it's finished - inaccurate results are useless
        }
        catch (InterruptedException ie) {
            throw new IllegalStateException(ie);
        }

        long total = 0;
        for (Job job : jobs) total += job.subtotal;
        return total;
    }

    private static int genPermsInner(int idx, int usedMask, int[] a, int[][] perms, int off) {
        if (idx == a.length) perms[off++] = a.clone();
        else for (int i = 0; i < a.length; i++) {
            int m = 1 << (a[idx] = i);
            if ((usedMask & m) == 0) off = genPermsInner(idx+1, usedMask | m, a, perms, off);
        }
        return off;
    }

    static class Job implements Runnable {
        private volatile long subtotal = 0;
        private final int n;
        private final int[][] perms;
        private final int shift;
        private final Map<CanonicalMatrix, Integer> unseen;

        public Job(int n, int[][] perms, int shift, Map<CanonicalMatrix, Integer> unseen) {
            this.n = n;
            this.perms = perms;
            this.shift = shift;
            this.unseen = unseen;
        }

        public void run() {
            long result = 0;
            int[][] perms = this.perms;
            Map<CanonicalMatrix, Integer> unseen = this.unseen;
            while (!unseen.isEmpty()) {
                int m = unseen.values().iterator().next();
                Set<CanonicalMatrix> equiv = new HashSet<CanonicalMatrix>();
                for (int[] perm : perms) {
                    CanonicalMatrix canonical = new CanonicalMatrix(m, perm);
                    if (equiv.add(canonical)) {
                        result += canonical.weight() << shift;
                        unseen.remove(canonical);
                    }
                }
            }

            subtotal = result;
        }
    }

    static class CanonicalMatrix {
        private final int[] a;
        private final int hash;

        public CanonicalMatrix(int m, int[] r) {
            this(permuteRows(m, r));
        }

        public CanonicalMatrix(int[] a) {
            this.a = a;
            Arrays.sort(a);

            int h = 0;
            for (int i : a) h = h * 37 + i;
            hash = h;
        }

        private static int[] permuteRows(int m, int[] perm) {
            int[] cols = new int[perm.length];
            for (int i = 0; i < perm.length; i++) {
                for (int j = 0; j < cols.length; j++) cols[j] |= ((m >> (perm[i] + j)) & 1L) << i;
            }
            return cols;
        }

        public int sum() {
            int sum = 0;
            for (int i : a) sum += i;
            return sum;
        }

        public int weight() {
            int prev = -1, count = 0, weight = FACT[a.length];
            for (int col : a) {
                if (col == prev) weight /= ++count;
                else {
                    prev = col;
                    count = 1;
                }
            }
            return weight;
        }

        @Override public boolean equals(Object obj) {
            // Deliberately unsuitable for general-purpose use, but helps catch bugs faster.
            CanonicalMatrix that = (CanonicalMatrix)obj;
            for (int i = 0; i < a.length; i++) {
                if (a[i] != that.a[i]) return false;
            }
            return true;
        }

        @Override public int hashCode() {
            return hash;
        }
    }
}

হিসাবে সংরক্ষণ করুন, হিসাবে HankelCombinatorics.javaসংকলন, হিসাবে javac HankelCombinatorics.javaচালানো java -Xmx2G HankelCombinatorics

সঙ্গে NUM_THREADS = 4আমার কোয়াড-কোর মেশিনে এটি পায় 20420819767436জন্য n=850 55 সেকেন্ড অতিবাহিত, রান মধ্যে পরিবর্তনশীলতা ন্যায্য পরিমাণ সঙ্গে; আমি আশা করি এটি আপনার অক্টা-কোর মেশিনে সহজেই পরিচালনা করা উচিত তবে এটি পেতে এক ঘন্টা বা আরও বেশি সময় লাগবে n=9

কিভাবে এটা কাজ করে

দেওয়া আছে n, 2^(2n-1)বাইনারি nএক্স nহান্কেল ম্যাট্রিক্স রয়েছে। সারিগুলি n!পদ্ধতিতে এবং কলামগুলিকে বিভিন্নভাবে অনুমতি দেওয়া যেতে পারে n!। আমাদের যা করতে হবে তা হ'ল দ্বিগুণ গণনা এড়ানো ...

আপনি যদি প্রতিটি সারির যোগফল গণনা করেন, তবে সারিগুলিকে অনুমতি দেওয়া বা কলামগুলিকে অনুমতি দেওয়ার ফলে অঙ্কের মাল্টিসেট পরিবর্তন হয় না। যেমন

0 1 1 0 1
1 1 0 1 0
1 0 1 0 0
0 1 0 0 1
1 0 0 1 0

সারি সমষ্টি মাল্টিসেট রয়েছে {3, 3, 2, 2, 2}এবং তাই এ থেকে প্রাপ্ত সমস্ত হ্যাঙ্কেলেবল ম্যাট্রিকেসও রয়েছে। এর অর্থ হ'ল আমরা হ্যান্কেল ম্যাট্রিককে এই সারির যোগফলগুলি বহু গোষ্ঠীগুলির দ্বারা গ্রুপ করতে পারি এবং তারপরে একাধিক প্রসেসরের কোরগুলি শোষণ করে প্রতিটি গ্রুপকে স্বাধীনভাবে পরিচালনা করতে পারি।

একটি শোষণীয় প্রতিসাম্যতাও রয়েছে: শূন্যের চেয়ে বেশি শূন্যের সাথে ম্যাট্রিকগুলি মূত্রের চেয়ে শূন্যের চেয়ে বেশি ম্যাট্রিকগুলির সাথে মায়ার করা হয়।

ডাবল কাউন্টিং ঘটে যখন Hankel ম্যাট্রিক্স M_1সারি বিন্যাস সঙ্গে r_1এবং কলাম বিন্যাস c_1Hankel ম্যাট্রিক্স সাথে মেলে M_2সারি বিন্যাস সঙ্গে r_2এবং কলাম বিন্যাস c_2(দুই পর্যন্ত সঙ্গে কিন্তু সব তিনটি M_1 = M_2, r_1 = r_2, c_1 = c_2)। সারি ও কলাম একাধিক বিন্যাসন স্বাধীন হয়, তাই আমরা যদি সারি বিন্যাস প্রয়োগ r_1করতে M_1এবং সারি বিন্যাস r_2করতে M_2, কলাম multisets যেমন সমান হতে হবে। সুতরাং প্রতিটি গ্রুপের জন্য, আমি গ্রুপে একটি ম্যাট্রিক্সে একটি সারি ক্রমায়ন প্রয়োগ করে প্রাপ্ত সমস্ত কলাম মাল্টিসেটগুলি গণনা করি। মাল্টিসেটগুলির একটি প্রাসঙ্গিক উপস্থাপনা পাওয়ার সহজ উপায় হ'ল কলামগুলি বাছাই করা এবং এটি পরবর্তী পদক্ষেপেও কার্যকর।

স্বতন্ত্র কলামের মাল্টিলেটগুলি পেয়ে, আমাদের খুঁজে বের করতে হবে যে n!প্রত্যেকের কতগুলি আদেশের অনন্যতা রয়েছে। এই মুহুর্তে, ডাবল-কাউন্টিং কেবল তখনই ঘটতে পারে যখন কোনও প্রদত্ত কলাম মাল্টিসেটে সদৃশ কলাম রয়েছে: আমাদের যা করার দরকার তা হ'ল মাল্টিসেটে প্রতিটি স্বতন্ত্র কলামের সংখ্যার সংখ্যা গণনা করা এবং তারপরে সংশ্লিষ্ট বহু-জাতীয় সহগের গণনা করা। যেহেতু কলামগুলি বাছাই করা হয়েছে, তাই গণনা করা সহজ।

অবশেষে আমরা তাদের সব যোগ করি।

অ্যাসিপটোটিক জটিলতা সম্পূর্ণ নির্ভুলতার সাথে গণনা করার জন্য তুচ্ছ নয়, কারণ আমাদের সেটগুলি সম্পর্কে কিছু অনুমান করা দরকার। আমরা প্রত্যেকের জন্য সময় লাগিয়ে (বাছাই সহ) 2^(2n-2) n!কলাম মাল্টিসেটের ক্রমের উপর মূল্যায়ন করি n^2 ln n; গ্রুপিং যদি কোনও ln nফ্যাক্টরের চেয়ে বেশি না নেয় তবে আমাদের সময় জটিলতা রয়েছে Theta(4^n n! n^2 ln n)। তবে যেহেতু ঘাতক উপাদানগুলি বহুত্বীয় উপাদানগুলিতে সম্পূর্ণরূপে আধিপত্য বিস্তার করে, তাই এটি Theta(4^n n!) = Theta((4n/e)^n)


এটি খুব চিত্তাকর্ষক। আপনি যে অ্যালগরিদম ব্যবহার করেছেন তা সম্পর্কে কিছু বলতে পারেন?

3

Python2 / 3

খুব ধীরে ধীরে সহজ ভাষায়,

import itertools

def permute_rows(m):
    for perm in itertools.permutations(m):
        yield perm

def permute_columns(m):
    T = zip(*m)
    for perm in itertools.permutations(T):
        yield zip(*perm)

N = 1
while True:
    base_template = ["abcdefghijklmnopqrstuvwxyz"[i:i+N] for i in range(N)]

    templates = set()
    for c in permute_rows(base_template):
        for m in permute_columns(c):
            templates.add("".join("".join(row) for row in m))

    def possibs(free, templates):
        if free == 2*N - 1:
            return set(int(t, 2) for t in templates)

        s = set()
        for b in "01":
            new_templates = set(t.replace("abcdefghijklmnopqrstuvwxyz"[free], b) for t in templates)
            s |= possibs(free + 1, new_templates)

        return s

    print(len(possibs(0, templates)))
    N += 1

টাইপ করে চালান python script.py


আপনার পাইথন 2/3 হিসাবে ভাষাটি তালিকাভুক্ত রয়েছে তবে পাইথন 2 এ কাজ করার জন্য আপনার কি দরকার নেই from __future__ import print_function(বা এর মতো কিছু)?
অ্যালেক্স এ

2
@AlexA। সাধারণত, হ্যাঁ, তবে এই ক্ষেত্রে নয়। টাইপ করার সময় পাইথন 2 এর আচরণ বিবেচনা করুন return(1)। এখন প্রতিস্থাপন returnসঙ্গে print:)
orlp

শান্ত! আমি প্রতিদিন নতুন কিছু শিখি. :)
অ্যালেক্স এ।

2

Haskell,

import Data.List
import Data.Hashable
import Control.Parallel.Strategies
import Control.Parallel
import qualified Data.HashSet as S

main = mapM putStrLn $ map (show.countHankellable) [1..]

a§b=[a!!i|i<-b]

hashNub :: (Hashable a, Eq a) => [a] -> [a]
hashNub l = go S.empty l
    where
      go _ []     = []
      go s (x:xs) = if x `S.member` s then go s xs
                                    else x : go (S.insert x s) xs

pmap = parMap rseq

makeMatrix :: Int->[Bool]->[[Bool]]
makeMatrix n vars = [vars§[i..i+n-1]|i<-[0..n-1]]

countHankellable :: Int -> Int
countHankellable n = let
    s = permutations [0..n-1]
    conjugates m = concat[permutations[r§q|r<-m]|q<-s]
    variableSets = sequence [[True,False]|x<-[0..2*(n-1)]]
 in
    length.hashNub.concat.pmap (conjugates.makeMatrix n ) $ variableSets

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

$ ghc -threaded hankell.hs
$ ./hankell

একটি হাস্কেল উত্তর সর্বদা স্বাগত। ধন্যবাদ.

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