सेलुलर ऑटोमेटा के साथ बहुलता मतदान


31

सेलुलर ऑटोमेटा में एक बहुत महत्वपूर्ण समस्या है जिसे मेजोरिटी समस्या कहा जाता है :

बहुसंख्यक समस्या, या घनत्व वर्गीकरण कार्य एक आयामी सेलुलर ऑटोमेटोन नियमों को खोजने की समस्या है जो बहुसंख्यक मतदान करते हैं।

...

I + j कोशिकाओं के साथ दो-राज्य सेलुलर ऑटोमेटा के कॉन्फ़िगरेशन को देखते हुए, जिनमें से i शून्य स्थिति में हैं और जिनमें से j एक राज्य में हैं, मतदान की समस्या का एक सही समाधान अंततः सभी कोशिकाओं को शून्य पर सेट करना होगा यदि i> j और अंत में सभी कोशिकाओं को एक सेट करना होगा अगर i <j। वांछित स्थिति राज्य अनिर्दिष्ट है यदि i = j।

हालांकि यह साबित हो चुका है कि कोई भी सेलुलर ऑटोमेटा सभी मामलों में बहुमत की समस्या को हल नहीं कर सकता है, लेकिन कई नियम हैं जो इसे अधिकांश मामलों में हल कर सकते हैं। Gacs-Kurdyumov-Levin automaton में यादृच्छिक प्रारंभिक स्थितियों के साथ लगभग 78% सटीकता है। GKL नियम जटिल नहीं है:

  • 3 की त्रिज्या, जिसका अर्थ है कि कोशिका की नई स्थिति 7 पिछली कोशिकाओं पर निर्भर करती है: स्वयं, दाईं ओर 3 कोशिकाएं और बाईं ओर 3 कोशिकाएं।
  • यदि कोई सेल वर्तमान में है O, तो उसका नया राज्य स्वयं का बहुमत है, सेल उसके बाईं ओर है, और सेल उसके बाईं ओर 3 कदम है।
  • यदि कोई सेल वर्तमान में है 1, तो इसकी नई स्थिति स्वयं का बहुमत है, सेल इसके दाईं ओर और सेल 3 इसके दाईं ओर स्थित है।

यहाँ एक उदाहरण है:

0 1 0 1 1 1 0 1 1 0 1 0 0 1
0 1 1 1 1 1 1 1 0 0 1 1 0 0
0 1 1 1 1 1 1 1 1 0 1 0 0 0
0 1 1 1 1 1 1 1 0 1 0 1 0 0
0 1 1 1 1 1 1 0 1 0 1 0 1 0
0 1 1 1 1 1 0 1 0 1 0 1 1 1
1 1 1 1 1 0 1 0 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

इस उदाहरण में, सेलुलर ऑटोमेटन ने सही ढंग से गणना की कि 8> 6. अन्य उदाहरणों में अधिक समय लगता है, और इस बीच कुछ शांत पैटर्न का उत्पादन होता है। नीचे दो उदाहरण हैं जो मुझे यादृच्छिक रूप से मिले हैं।

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

इसे अगले स्तर पर ले जाना

जहां तक ​​मेरे इंटरनेट अनुसंधान से पता चला है, बहुमत की समस्या पर लगभग सभी अकादमिक अनुसंधान 2-राज्य सीए के साथ आयोजित किए गए हैं। इस चुनौती में, हम 3-राज्य CAs के लिए बहुसंख्यक समस्या का विस्तार करने जा रहे हैं । मैं इसे बहुलता समस्या कहूंगा । बहुलता , या सापेक्ष बहुमत, उस स्थिति को संदर्भित करता है, जिसमें किसी एक विकल्प में प्रत्येक विकल्प की तुलना में अधिक वोट होते हैं, लेकिन जरूरी नहीं कि सभी वोटों का बहुमत हो।

समस्या का विवरण

  1. त्रिज्या 3 के साथ 3-राज्य 1 डी सेलुलर ऑटोमेटन है।
  2. कर रहे हैं 151 एक परिपत्र सीमा शर्त के साथ कोशिकाओं।
  3. इन कोशिकाओं को एक यादृच्छिक शुरुआती राज्य दिया जाता है, एकमात्र शर्त पर कि 3 राज्यों में से 1 में एक सख्त बहुलता है। "यादृच्छिक" का अर्थ है प्रत्येक कोशिका के लिए एक स्वतंत्र समान वितरण।
  4. एक नियम की सटीकता (प्रारंभिक) यादृच्छिक प्रारंभिक स्थितियों का प्रतिशत है जिसमें सभी कोशिकाएं 10000 पीढ़ियों के भीतर सही स्थिति (बहुलता के साथ) के लिए सिंक्रनाइज़ होती हैं ।
  5. लक्ष्य उच्च सटीकता के साथ एक नियम खोजना है,

बहुलता के किनारे के मामले: 50/50/51 के साथ कोई भी विन्यास एक वैध आरंभिक विन्यास है (क्योंकि एक सख्त बहुलता है), जबकि 51/51/49 के साथ कोई भी विन्यास वैध नहीं है (क्योंकि कोई सख्त बहुलता नहीं है)।

खोज स्थान 3 ^ 3 ^ 7 (~ 3e1043) है, किसी भी विस्तृत खोज की पहुंच से बाहर। इसका मतलब है कि आपको इस समस्या को हल करने के लिए आनुवंशिक एल्गोरिदम जैसी अन्य तकनीकों का उपयोग करने की आवश्यकता होगी। यह कुछ मानव इंजीनियरिंग भी ले जाएगा।

10000 पीढ़ी का नियम परिवर्तन के अधीन है, जो नियम या नियम लोगों की सटीकता पर निर्भर करता है। यदि अभिसरण की उचित दरों की अनुमति देना बहुत कम है, तो मैं इसे बढ़ा सकता हूं। वैकल्पिक रूप से, मैं इसे एक टाई-ब्रेकर के रूप में सेवा करने के लिए कम कर सकता हूं।

जीतना

विजेता वह व्यक्ति है जो सभी प्रतियोगियों में से उच्चतम सटीकता के साथ त्रिज्या -3 सीए नियम प्रस्तुत करता है।

आपके सबमिशन में शामिल होना चाहिए ...

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

काम से पहले

  • जुइल और पोलाक द्वारा एक पेपर , जिसमें वर्णित है कि उन्होंने 86% सटीकता के साथ 2-राज्य शासन कैसे विकसित किया।
  • इस पेपर में r = 3, 149-सेल, 2-स्टेट CA का उपयोग किया गया था। हालांकि, यह बहुसंख्यक समस्या को हल करने का प्रयास नहीं करता था, लेकिन इसके बजाय उन नियमों को खोजने के लिए जो जल्दी-जल्दी एक सभी 1- 0पैटर्न में परिणत होते थे । इन मतभेदों के बावजूद, मुझे संदेह है कि कई तकनीकें समान होंगी।
  • वोल्ज़ और डी ओलिविएरा द्वारा ए (बहुत उपयोगी नहीं है क्योंकि यह एक पेवल के पीछे है) पेपर जो वर्तमान में 2-राज्य रिकॉर्ड रखता है

मुझे यह देखकर बहुत निराशा हुई / आश्चर्य हुआ कि इसका बहुलता वोटिंग से कोई लेना-देना नहीं है ।
बिल्ली

2
@ मुझे वास्तव में ऐसा लगता है जैसे यह करता है। प्रत्येक सेल का राज्य अपने "वोट" (3 उम्मीदवारों में से 1 का विकल्प) का प्रतिनिधित्व कर सकता है, और लक्ष्य चुनाव के विजेता को निर्धारित करना है।
PhiNotPi

2
यह एक दिलचस्प कोड चुनौती है। मैं एक गोल्फ खिलाड़ी नहीं हूं, इसलिए इस तरह की पहेलियों को देखना हमेशा खुशी देता है।
ड्रेको

जवाबों:


6

GKL के साथ-साथ पहाड़ी चढ़ाई, 61.498%

  • यदि एक सेल 0 है, तो कोशिकाओं को 3 को बाईं ओर, 1 को बाईं ओर और खुद को देखें। बहुमत के लिए मूल्य निर्धारित करें। यदि यह एक टाई है, तो जिस तरह से आप हैं वैसे रहें।

  • यदि एक कोशिका 1 है, तो कोशिकाओं को 3 से दाईं ओर, 1 से दाईं ओर और स्वयं देखें। बहुमत के लिए मूल्य निर्धारित करें। यदि यह एक टाई है, तो जिस तरह से आप हैं वैसे रहें।

  • यदि एक सेल 2 है, तो कोशिकाओं को 2 से बाईं ओर, 2 को दाईं ओर और 3 को दाईं ओर देखें। बहुमत के लिए मूल्य निर्धारित करें। यदि यह एक टाई है, तो जिस तरह से आप हैं वैसे रहें।

मुझे कुल 100000 में से 59453 अधिकार मिले, 59.453%

कुछ उत्परिवर्तन और पहाड़ी-चढ़ाई 61498/100000 = 61.498% हुई।

मैं शायद थोड़ा और परीक्षण करूंगा और बाद में कुछ और जानकारी पोस्ट करूंगा।


3
आपको वास्तविक 61.498% नियम को शामिल करना चाहिए ताकि लोग इसे सत्यापित कर सकें।
मार्टिन एंडर

आपको (आप) परीक्षण शायद करना चाहिए।
को आउटगोल्फर से एरिक

5

"बस 2s टॉस करें और GKL करें" - 55.7%

यह अनुमान लगाना इतना आसान नहीं है कि एक अच्छा नियम क्या होगा, इसलिए मैंने कम से कम कुछ ऐसा करने की कोशिश की, जो 1/3 से ऊपर हो। रणनीति यह है कि बहुमत राज्य 0 या 1 होने पर सही उत्तर प्राप्त करने का प्रयास किया जाए, और यदि यह 2 है तो नुकसान को स्वीकार करें। इसने 100,000 परीक्षणों पर 56.5% अंक प्राप्त किए, जो कि 78% से गुणा करने की उम्मीद से थोड़ा बेहतर है। जीकेएल का स्कोर) * 2/3 (उस समय का अंश जब उत्तर 0 या 1 हो) = 52%।

अधिक संक्षेप में, रणनीति इस प्रकार है:

  • यदि सेल 0 या 1 है, तो 3 कोशिकाओं में से अधिकांश को GKL रणनीति के अनुसार लें, लेकिन किसी भी पड़ोसी को अनदेखा करें जो 2 हैं। यदि यह एक टाई है, तो सेल को अपरिवर्तित छोड़ दें।
  • यदि सेल 2 है, तो पूरे पड़ोस में 0 या 1 में से जो भी अधिक हो, चुनें। यदि यह टाई है, तो बाईं ओर का मान 0 या 1 चुनें। यदि सभी पड़ोसी 2 हैं, तो 2 रहें।

मैंने परीक्षण करने के लिए इस कोड का उपयोग किया:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <random>
#include <cassert>

#define W 151
#define S 3
#define R 3

typedef int state;

struct tape {
    state s[R+W+R];
    state& operator[](int i) {
        return s[i + R];
    }
    template<typename Rule> void step(Rule r) {
        for(int i = 0; i < R; i++) s[i] = s[W + i];
        for(int i = 0; i < R; i++) s[R + W + i] = s[R + i];
        for(int i = 0; i < W; i++) {
            s[i] = r(s + R + i);
        }
        memmove(s + R, s, W * sizeof(*s));
    }

    state unanimous() {
        state st = (*this)[0];
        for(int i = 1; i < W; i++) {
            if((*this)[i] != st)
                return -1;
        }
        return st;
    }
};

std::ostream& operator<<(std::ostream& s, tape& t) {
    for (int i = 0; i < W; i++)
        s << t[i];
    return s;
}

state randomize(tape& t) {
    static std::mt19937 rg(390332);
    begin:
    int c[S]{};
    for(int i = 0; i < W; i++) {
        state s = rg() % S;
        c[s]++;
        t[i] = s;
    }
    state* smax = std::max_element(c, c + R);
    int nmaj = 0;
    for (int n : c) nmaj += n == *smax;
    if (nmaj > 1) goto begin;
    return smax - c;
}

template<bool PrintSteps, typename Rule> int simulate(Rule r, int trials, int giveup) {
    int successes = 0;
    for(state s = 0; s < S; s++) {
        state t[2 * R + 1];
        for(int i = 0; i <= 2 * R; i++) t[i] = s;
        assert(r(t + R) == s);
    }
    while(trials--) {
        tape tp;
        state desired = randomize(tp);
        int steps = giveup;
        while(steps--) {
            tp.step(r);
            state u = tp.unanimous();
            if(~u) {
                bool correct = u == desired;
                if(PrintSteps) {
                    std::cout << correct << ' ' << giveup - steps << '\n';
                }
                successes += correct;
                break;
            }
        }
    }
    return successes;
}


struct ixList {
    int n;
    int i[2 * R + 1];
};



state rule_justTossOutThe2sAndDoGKL(const state* t) {
    const ixList ixl[] = {
        { 3,{ -3, -1, 0 } },
        { 3,{ 0, 1, 3 } },
        { 6,{ -3, -2, -1, 1, 2, 3 } } 
    };
    int c[S]{};
    for (int i = 0; i < ixl[*t].n; i++)
        c[t[ixl[*t].i[i]]]++;
    if (c[0] > c[1]) return 0;
    if (c[1] > c[0]) return 1;
    if (*t < 2) return *t;
    for (int i = -R; i <= R; i++)
        if (t[i] < 2) return t[i];
    return 2;
}

int main()
{
    int nt = 100000;
    int ns = simulate<false>(rule_justTossOutThe2sAndDoGKL, nt, 10000);

    std::cout << (double)ns / nt << '\n';
    return 0;
}

स्कोर आपकी अपेक्षा से अधिक है क्योंकि यह पीढ़ी की सीमा के साथ बढ़ता है। जीकेएल का 78% स्कोर वास्तव में एक सौ सौ या तो बहुत कम सीमा के लिए है। इसके विपरीत, 10,000 gens GKL को एक उच्च सटीकता दर प्रदान करते हैं, संभवतः आपके द्वारा प्राप्त किए जा रहे परिणामों के अनुरूप।
PhiNotPi

2

"बस जो भी सबसे अच्छा है उसे चोरी करें और इसे विकसित करें", ब्लोह

संपादित करें: अपनी वर्तमान स्थिति में यह उत्तर बेहतर पैटर्न खोजने के बजाय, एक बेहतर यादृच्छिक नमूना पाता है।

यह उत्तर सभी राज्यों को त्रैमासिक संख्याओं (कम से कम महत्वपूर्ण अंक) के रूप में गणना करके समाधान / डिकोड करता है। 59.2% के लिए समाधान:

000000000010010010000000000000000000000000000000000000000000010000010000110000000
000000000010010010000000000111111101111111111111111111000011000010011011000011010
000000000012010011001000000021111111111120111211111111000000000000011010000010000
000011000010022110000000202000000002000000000020000000001010000000011011000011010
020000000010010010001000000111101111111111111111111111010011000011111111010011010
000000000010010010000000000111111111101111111111112111000011010110111011010011011
000000000010010010000000000010000000000000000100002011000000000100011010020010000
000020020010010010000200000111102111111111111111111101000011010010111011000011011
000100000010010010000000000121111111111111111111111111000210000012011011002011010
000000000010010110000000000111112112111111111001111111000010000010011011000011010
000000000010010120000200000111211111111111111111110111110011010011100111010011011
000000000010010010000000000011111111111111111111111111000011010010111211210012020
010000000010010010020100020111110111111111111111111110010111010011011111010111011
002000000010010010000000000111110111111111211111111111001111111111111111111111111
000000000110010010000000000111111111111111211111111111010111011111111111011111011
001000000010010010000000000011111101111111111111110111000011010010111011010011010
001000000010010110000000000111111111111111102111110111010111011111111111011111101
000000000210010010000000000111111111111111111111011111010011010011111111010111011
000000000010010010000000000112111111111111111111101011000000000000011010000010000
000000000010010010000000000111111111111111111111111111000011010010111011010011011
000200000012010010000000000111111111111112111111111111000010000210011211001011010
000000000010010211000002000111111111111111111111111111000001010010111011010011010
000021200010210010000101100111111111111211111110110211010111021111111101010111111
000000000010010010000000000111111111111101111111111111010011010111111111010110021
000200000010010010000000010111111111101111111121112111000210001010011011000011010
000000000010010010000000000111111111111111111111111111210011010021111111010111011
000020000010010010000000000111111111111111111111111111000011010010121011010011012

यह उत्तर निम्नलिखित कोड का उपयोग करते हुए feersum के 55.7% से विकसित किया गया था। इस कोड में लिबोप की आवश्यकता होती है , जो कि मेरा व्यक्तिगत C ++ हैडर-ओनली लाइब्रेरी है। इसे स्थापित करना बहुत आसान है, बस git clone https://github.com/orlp/libopउसी निर्देशिका में करें जहां आपने प्रोग्राम सहेजा है। मैं संकलन करने का सुझाव देता हूं g++ -O2 -m64 -march=native -std=c++11 -g। तेजी से विकास के लिए, मैं भी उपरोक्त कमांड को चलाकर कामवासना को बढ़ाने का सुझाव देता हूं libop/op.h

#include <cstdint>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <random>

#include "libop/op.h"

constexpr int MAX_GENERATIONS = 500;
constexpr int NUM_CELLS = 151;

std::mt19937_64 rng;

double worst_best_fitness;

// We use a system with okay-ish memory density. We represent the ternary as a
// 2-bit integer. This means we have 32 ternaries in a uint64_t.
//
// There are 3^7 possible states, requiring 4374 bits. We store this using 69
// uint64_ts, or little over half a kilobyte.

// Turn 7 cells into a state index, by encoding as ternary.
int state_index(const int* cells) {
    int idx = 0;
    for (int i = 0; i < 7; ++i) {
        idx *= 3;
        idx += cells[6-i];
    }
    return idx;
}

// Get/set a ternary by index from a 2-bit-per-ternary encoded uint64_t array.
int get_ternary(const uint64_t* a, size_t idx) {
    return (a[idx/32] >> (2*(idx % 32))) & 0x3;
}

void set_ternary(uint64_t* a, size_t idx, int val) {
    assert(val < 3);
    int shift = 2*(idx % 32);
    uint64_t shifted_val = uint64_t(val) << shift;
    uint64_t shifted_mask = ~(uint64_t(0x3) << shift);
    a[idx/32] = (a[idx/32] & shifted_mask) | shifted_val;
}


struct Rule {
    uint64_t data[69];
    double cached_fitness;

    Rule(const char* init) {
        cached_fitness = -1;
        for (auto i : op::range(69)) data[i] = 0;
        for (auto i : op::range(2187)) set_ternary(data, i, init[i] - '0');
    }

    double fitness(int num_tests = 1000);

    Rule* random_mutation(int num_mutate) const {
        auto new_rule = new Rule(*this);

        auto r = op::range(2187);
        std::vector<int> indices;
        op::random_sample(r.begin(), r.end(),
                          std::back_inserter(indices), num_mutate, rng);

        for (auto idx : indices) {
            set_ternary(new_rule->data, idx, op::randint(0, 2, rng));
        }

        new_rule->cached_fitness = -1;
        return new_rule;
    }

    int new_state(const int* cells) const {
        return get_ternary(data, state_index(cells));
    }

    void print_rule() const {
        for (auto i : op::range(2187)) {
            std::cout << get_ternary(data, i);
            if (i % 81 == 80) std::cout << "\n";
        }
    }
};


struct Automaton {
    uint64_t state[5];
    int plurality, generation;

    Automaton() : generation(0) {
        for (auto i : op::range(5)) state[i] = 0;

        int strict = 0;
        while (strict != 1) {
            int votes[3] = {};
            for (auto i : op::range(NUM_CELLS)) {
                int vote = op::randint(0, 2, rng);
                set_ternary(state, i, vote);
                votes[vote]++;
            }

            // Ensure strict plurality.
            plurality = std::max_element(votes, votes + 3) - votes;
            strict = 0;
            for (auto i : op::range(3)) strict += (votes[i] == votes[plurality]);
        }
    }

    void print_state() {
        for (int i = 0; i < 151; ++i) std::cout << get_ternary(state, i);
        std::cout << "\n";
    }

    bool concensus_reached() {
        int target = get_ternary(state, 0);
        for (auto i : op::range(NUM_CELLS)) {
            if (get_ternary(state, i) != target) return false;
        }

        return true;
    }

    void next_state(const Rule& rule) {
        uint64_t new_state[5] = {};

        std::vector<int> cells;
        for (auto r : op::range(-3, 4)) {
            cells.push_back(get_ternary(state, (r + NUM_CELLS) % NUM_CELLS));
        }

        for (auto i : op::range(NUM_CELLS)) {
            set_ternary(new_state, i, rule.new_state(cells.data()));
            cells.erase(cells.begin());
            cells.push_back(get_ternary(state, (i + 4) % NUM_CELLS));
        }

        for (auto i : op::range(5)) state[i] = new_state[i];
        generation++;
    }
};


double Rule::fitness(int num_tests) {
    if (cached_fitness == -1) {
        cached_fitness = 0;
        int num_two = 0;
        for (auto test : op::range(num_tests)) {
            Automaton a;
            while (a.generation < MAX_GENERATIONS && !a.concensus_reached()) {
                a.next_state(*this);
            }

            if (a.generation < MAX_GENERATIONS &&
                get_ternary(a.state, 0) == a.plurality &&
                a.plurality == 2) num_two++;

            cached_fitness += (a.generation < MAX_GENERATIONS &&
                               get_ternary(a.state, 0) == a.plurality);

            if (cached_fitness + (num_tests - test) < worst_best_fitness) break;
        }

        if (num_two) std::cout << cached_fitness << " " << num_two << "\n";

        cached_fitness;
    }

    return cached_fitness;
}



int main(int argc, char** argv) {
    std::random_device rd;
    rng.seed(42); // Seed with rd for non-determinism.

    const char* base = 
        "000000000010010010000000000000000000000000000000000000000000000000010000000000000"
        "000000000010010010000000000111111111111111111111111111000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111000000000000011010000010000"
        "000000000010010010000000000000000000000000000000000000000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011011"
        "000000000010010010000000000000000000000000000000000000000000000000011010000010000"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011011"
        "000000000010010010000000000111111111111111111111111111000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011010"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111011111111111111111111111111"
        "000000000010010010000000000111111111111111111111111111010111011111111111011111111"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011010"
        "000000000010010010000000000111111111111111111111111111010111011111111111011111111"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111000000000000011010000010000"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011011"
        "000000000010010010000000000111111111111111111111111111000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011010"
        "000000000010010010000000000111111111111111111111111111010111011111111111011111111"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111000010000010011011000011010"
        "000000000010010010000000000111111111111111111111111111010011010011111111010111011"
        "000000000010010010000000000111111111111111111111111111000011010010111011010011012"
    ;

    // Simple best-only.
    std::vector<std::unique_ptr<Rule>> best_rules;
    best_rules.emplace_back(new Rule(base));
    worst_best_fitness = best_rules.back()->fitness();
    while (true) {
        const auto& base = *op::random_choice(best_rules.begin(), best_rules.end(), rng);
        std::unique_ptr<Rule> contender(base->random_mutation(op::randint(0, 100, rng)));

        // Sort most fit ones to the beginning.
        auto most_fit = [](const std::unique_ptr<Rule>& a, const std::unique_ptr<Rule>& b) {
            return a->fitness() > b->fitness();
        };

        if (contender->fitness() >= best_rules.back()->fitness()) {
            std::cout << contender->fitness();
            double contender_fitness = contender->fitness();
            best_rules.emplace_back(std::move(contender));
            std::sort(best_rules.begin(), best_rules.end(), most_fit);
            if (best_rules.size() > 5) best_rules.pop_back();
            std::cout << " / " << best_rules[0]->fitness() << "\n";
            worst_best_fitness = best_rules.back()->fitness();

            if (contender_fitness == best_rules.front()->fitness()) {
                best_rules.front()->print_rule();
            }
        }
    }

    return 0;
}

0

हैंड कोडेड, 57.541%

यह वास्तव में केवल इसके ऊपर की 5 कोशिकाओं को देखता है। यह जिस रेंज में दिखता है उसे बढ़ाकर शायद इसे बेहतर बनाया जा सकता है। 100,000 परीक्षण मामलों के साथ भाग गया।

कलन विधि:

If above == 0:
   if to the left there are only 2s or there is a 1 separated by 2s
       next state = 2
   else
       next state = 0
If above == 1:
   if to the right there are only 2s or there is a 0 separated by 2s
       next state = 2
   else
       next state = 1
If above == 2:
   ignore 0s to the left if the 0 is left of a 1 on the left
   ignore 1s to the right if the 1 is right of a 0 on the right
   if the closest 0 on the left is closer than the closest 1 on the right
       next state = 0
   else if the closest 1 on the right is closer than the closest 0 on the left
       next state = 1
   else
       next state = 2

जीन:

000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222222222222222222222222222222000000000222222222222222222
000000000222222222000222222111111111111111111111111111222111111111111111111111111
000000000222222222000222222111111111111111111111111111000000000111111111222111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222222222222222222222222222222000000000222222222222222222
000000000222222222000222222111111111111111111111111111222111111111111111111111111
000000000222222222000222222111111111111111111111111111000000000111111111222111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222222222222222222222222222222000000000222222222222222222
000000000222222222000222222111111111111111111111111111222111111111111111111111111
000000000222222222000222222111111111111111111111111111000000000111111111222111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222
000000000222222222000222222111111111111111111111111111000222222111111111111111111
000000000222222222000222222222222222222222222222222222000000000222222222000222222

परीक्षण कोड:

import java.lang.Math.*
import java.util.*

const val RADIUS = 3;
const val STATES = 3;
const val DIAMETER = 2 * RADIUS + 1
const val TAPE_LENGTH = 151

val CODE_SIZE = pow(STATES.toDouble(), DIAMETER.toDouble()).toInt()

const val GRADE_RUNS = 100000
const val GRADE_MAX_TIME = 10000


operator fun IntArray.inc() : IntArray {
    val next = this.clone()
    var i = 0
    while (i < size) {
        if (this[i] == STATES - 1) {
            next[i] = 0
        } else {
            next[i]++
            break
        }
        i++
    }
    return next
}
val IntArray.index : Int
    get() {
        var total = 0
        for (i in (size - 1) downTo 0) {
            total *= STATES
            total += this[i]
        }
        return total
    }

interface IRule {
    operator fun get(states : IntArray) : Int
}

fun IntArray.equalsArray(other: IntArray) = Arrays.equals(this, other)

class Rule : IRule {

    constructor(rule : IRule) {
        val start = IntArray(DIAMETER)
        var current = start.clone()

        code = IntArray(CODE_SIZE)
        try {
            do {
                code[current.index] = rule[current]
                current++
            } while (!current.equalsArray(start));
        } catch (e : Throwable) {
            println(Arrays.toString(code))
            println(Arrays.toString(current))
            throw e
        }
    }
    constructor(code : IntArray) {
        this.code = IntArray(CODE_SIZE) { if (it < code.size) code[it] else 0 }
    }

    val code : IntArray

    override fun get(states: IntArray) : Int {
        return code[states.index]
    }

    override fun toString() : String {
        val b = StringBuilder()
        for (i in 0 until CODE_SIZE) {
            if (i > 0 && i % pow(STATES.toDouble(), RADIUS.toDouble() + 1).toInt() == 0) {
                b.append('\n')
            }
            b.append(code[i])
        }
        return b.toString()
    }

    fun grade() : Double {
        var succeeded = 0
        for (i in 0 until GRADE_RUNS) {
            if (i % (GRADE_RUNS / 100) == 0) {
                println("${i/(GRADE_RUNS / 100)}% done grading.")
            }
            var tape : Tape
            do {
                tape = Tape()
            } while (tape.majority() == -1);
            val majority = tape.majority()
            val beginning = tape
            var j = 0
            while (j < GRADE_MAX_TIME && !tape.allTheSame()) {
                tape = tape.step(this)
                j++
            }
            if (tape.stabilized(this) && tape.majority() == majority) {
                succeeded++
            }/* else if (beginning.majority() != 2) {
                println(beginning.majority())
                tape = beginning
                for (j in 1..100) {
                    println(tape)
                    tape = tape.step(this)
                }
                println(tape)
            }*/
        }
        return succeeded.toDouble() / GRADE_RUNS
    }

}

fun getRandomState() : Int {
    return (random() * STATES).toInt()
}

class Tape(val tape : IntArray) {

    constructor() : this(IntArray(TAPE_LENGTH) { getRandomState() } )

    fun majority() : Int {
        val totals = IntArray(STATES)

        for (cell in tape) {
            totals[cell]++
        }

        var best = -1
        var bestScore = -1

        for (i in 0 until STATES) {
            if (totals[i] > bestScore) {
                best = i
                bestScore = totals[i]
            } else if (totals[i] == bestScore) {
                best = -1
            }
        }

        return best
    }

    fun allTheSame() : Boolean {
        for (i in 1 until TAPE_LENGTH) {
            if (this[i] != this[0]) {
                return false
            }
        }
        return true
    }

    operator fun get(index: Int) = tape[((index % TAPE_LENGTH) + TAPE_LENGTH) % TAPE_LENGTH]

    fun step(rule : IRule) : Tape {
        val nextTape = IntArray ( TAPE_LENGTH )

        for (i in 0 until TAPE_LENGTH) {
            nextTape[i] = rule[IntArray(DIAMETER) { this[i + it - RADIUS] }]
        }

        return Tape(nextTape)
    }

    fun stabilized(rule : IRule) = allTheSame() && majority() == step(rule).majority()

    override fun toString() : String {
        val b = StringBuilder()
        for (cell in tape) {
            b.append(cell)
        }
        return b.toString()
    }

}

fun main(args : Array<String>) {
    val myRule = Rule(object : IRule {
        override fun get(states: IntArray): Int {
            if (states[3] == 0) {
                if (states[2] == 1) {
                    return 2
                } else if (states[2] == 0) {
                    return 0
                } else if (states[1] == 1) {
                    return 2
                } else if (states[1] == 0) {
                    return 0
                } else {
                    return 2
                }
            } else if (states[3] == 1) {
                if (states[4] == 0) {
                    return 2
                } else if (states[4] == 1) {
                    return 1
                } else if (states[5] == 0) {
                    return 2
                } else if (states[5] == 1) {
                    return 1
                } else {
                    return 2
                }
            } else {
                if (states[2] == 0) {
                    if (states[4] != 1) {
                        return 0
                    }
                } else if (states[4] == 1) {
                    return 1
                }
                if (states[1] == 0 && states[2] != 1) {
                    if (states[5] != 1) {
                        return 0
                    }
                } else if (states[5] == 1 && states[4] != 0) {
                    return 1
                }
                return 2
            }
        }

    })
    var tape = Tape()
    println(myRule.grade())
}

उदाहरण

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.