多数问题,即密度分类任务,是找到精确执行多数投票的一维元胞自动机规则的问题。..。给定一个两个状态的元胞自动机的结构,其中i处于零状态,j处于一种状态,投票问题的正确解决方案必须最终将所有单元格设置为零,如果i< j,则必须最终将所有单元格设置为1。如果i=j,所需的最终状态未指定。
尽管元胞自动机在所有情况下都不能解决大多数问题,但在大多数情况下,有许多规则可以解决。在随机初始条件下,自动机的精度约为78% .GKL规则并不复杂:
O,它的新状态是它自己的大部分,单元格在它的左边,单元格在它的左边。1,它的新状态是它自己的大部分,单元格在它的右边,单元格在它的右边。下面是一个示例:
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据我的互联网研究显示,几乎所有关于大多数问题的学术研究都是用两态CA进行的。在这一挑战中,我们将把多数问题扩大到三态CA。我把这称为“多数问题”。多数,或称相对多数,指的是一种情况,在这种情况下,其中一种选择拥有比每一种备选方案更多的选票,但不一定占所有选票的多数。
多个边缘情况:任何50/50/51的配置都是有效的启动配置(因为存在严格的多个),而任何51/51/49的配置都是无效的(因为没有严格的多个)。
搜索空间为3^3^7 (~3e1043),远远超出了任何穷尽搜索的范围。这意味着你需要利用其他技术,比如遗传算法,来解决这个问题。它也将需要一些人类工程。
10000生成规则可能会更改,这取决于人们发现的运行时/规则的准确性。如果它太低,不允许合理的收敛速度,我可以提高它。或者,我可以降低它作为一个平局。
获胜者是提交radius-3 CA规则的人,该规则在所有参赛者中具有最高的准确性。
你的意见应该包括..。
1全0模式交替的规则。尽管存在这些差异,但我怀疑许多技术将是相似的。发布于 2016-01-13 00:42:08
很难猜出一个好的规则会是什么,所以我试着至少想出一个分数在1/3以上的东西。策略是,当多数状态为0或1时,尝试得到正确的答案,如果是2,则接受损失。它在10万次试验中得分为56.5%,比78% (GKL的分数)* 2/3 (答案为0或1的时间的分数)= 52%的预期略好。
具体而言,该战略如下:
我用这段代码来测试:
#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;
}发布于 2016-01-13 04:55:20
编辑:在当前状态下,这个答案不是找到更好的模式,而是找到一个更好的随机样本。
此答案通过将所有状态枚举为三元数(最不重要的数字优先)来编码/解码解决方案。解决办法为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上运行上面的命令来预编译libop。
#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;
}发布于 2016-03-04 04:15:30
这实际上只看上面的5个细胞。它可能会通过增加它所观察的范围而得到改善。用100000个测试用例运行。
算法:
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())
}示例
https://codegolf.stackexchange.com/questions/69285
复制相似问题