1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-18 15:00:26 +00:00

rulegen3:: more improvements

This commit is contained in:
Zeno Rogue 2022-08-17 17:40:12 +02:00
parent a441ab474f
commit 80c3dfcd34

View File

@ -513,7 +513,19 @@ struct transducer_transitions {
inline void print(hstream& hs, transducer_transitions* h) { print(hs, "T", index_pointer(h)); }
inline void print(hstream& hs, const transducer_state& s) { print(hs, "S", tie(s.tstate1, s.tstate2, s.relation)); }
using transducer = map<transducer_state, transducer_transitions>;
template<class T> size_t hsh(T t) { return std::hash<T>()(t); }
struct tshash {
size_t operator() (const transducer_state& s) const {
size_t res = hsh(s.tstate1) ^ (hsh(s.tstate2) << 16);
res ^= size_t(s.relation) + 0x9e3779b9 + (res << 6) + (res >> 2);
return res;
}
};
using tpair = pair<const transducer_state, transducer_transitions>;
using transducer = std::unordered_map<transducer_state, transducer_transitions, tshash>;
transducer autom;
int comp_step;
@ -546,7 +558,15 @@ tcell* get_move(tcell *c, int dir) {
return c->cmove(dir);
}
struct tuplehash {
size_t operator() (const tuple<tcell*, int, int>& tu) const { return hsh(get<0>(tu)) + (hsh(get<1>(tu)) << 8) + (hsh(get<2>(tu)) << 16); }
};
std::unordered_map<tuple<tcell*, int, int>, tcell*, tuplehash> rmmemo;
tcell *rev_move2(tcell *t, int dir1, int dir2) {
auto& memo = rmmemo[{t, dir1, dir2}];
if(memo) return memo;
if(dir1 != ENDED) t = rev_move(t, dir1);
if(dir2 != ENDED) {
t = t->cmove(dir2);
@ -555,7 +575,7 @@ tcell *rev_move2(tcell *t, int dir1, int dir2) {
}
twalker tw = t; get_parent_dir(tw);
if(t->dist && t->parent_dir == MYSTERY) throw rulegen_failure("no parent_dir assigned after rev_move2!");
return t;
return memo = t;
}
vector<int> desc(tcell *t) {
@ -664,10 +684,20 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul
transducer_transitions *ires;
const transducer_transitions *t1;
const transducer_transitions *t2;
bool operator < (const searcher& s2) const { return tie(ts1, ts2, ts3, tat, fin1, fin2, fin3, ires, t1, t2) < tie(s2.ts1, s2.ts2, s2.ts3, s2.tat, s2.fin1, s2.fin2, s2.fin3, s2.ires, s2.t1, s2.t2); };
bool operator == (const searcher& s2) const { return tie(fin1, fin2, fin3, ires, t1, t2) == tie(s2.fin1, s2.fin2, s2.fin3, s2.ires, s2.t1, s2.t2); };
};
set<searcher> in_queue;
struct searchhash {
size_t operator() (const searcher& s) const {
size_t res = size_t(s.fin1+2*s.fin2+4*s.fin3);
res ^= size_t(s.ires) + 0x9e3779b9 + (res << 6) + (res >> 2);
res ^= size_t(s.t1) + 0x9e3779b9 + (res << 6) + (res >> 2);
res ^= size_t(s.t2) + 0x9e3779b9 + (res << 6) + (res >> 2);
return res;
}
};
std::unordered_set<searcher, searchhash> in_queue;
vector<searcher> q;
auto enqueue = [&] (const searcher& s) {
if(in_queue.count(s)) return;
@ -685,38 +715,20 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul
enqueue(sch);
}
int tdc = 0, tdc2 = 0;
for(int i=0; i<isize(q); i++) {
auto sch = q[i];
if(sch.t1->accepting_directions && sch.t2->accepting_directions)
sch.ires->accepting_directions = 1;
int dirs1 = isize(treestates[sch.ts1].rules);
int dirs2 = isize(treestates[sch.ts2].rules);
int dirs3 = isize(treestates[sch.ts3].rules);
searcher next;
for(int d1=ENDED; d1<dirs1; d1++) {
if(d1 != ENDED && sch.fin1) break;
auto r1 = get_abs_rule1(sch.ts1, d1);
if(r1 < 0) continue;
for(int d2=ENDED; d2<dirs2; d2++) {
if(d2 != ENDED && sch.fin2) break;
auto r2 = get_abs_rule1(sch.ts2, d2);
if(r2 < 0) continue;
next.t1 = sch.t1;
if(d1 != ENDED || d2 != ENDED) {
if(!sch.t1->t.count({d1, d2})) continue;
next.t1 = sch.t1->t.at({d1, d2});
}
for(int d3=ENDED; d3<dirs3; d3++) {
if(d3 != ENDED && sch.fin3) break;
auto r3 = get_abs_rule1(sch.ts3, d3);
if(r3 < 0) continue;
next.t2 = sch.t2;
if(d2 != ENDED || d3 != ENDED) {
if(!sch.t2->t.count({d2, d3})) continue;
next.t2 = sch.t2->t.at({d2, d3});
}
auto try_d3 = [&] (int d1, int d2, int r1, int r2) {
tdc++;
auto try_done = [&] (int d3, int r3) {
tdc2++;
next.ts1 = r1; next.fin1 = d1 == ENDED;
next.ts2 = r2; next.fin2 = d2 == ENDED;
next.ts3 = r3; next.fin3 = d3 == ENDED;
@ -728,10 +740,42 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul
next.ires = sch.ires->t[{d1, d3}] = &(result[nstate_key]);
enqueue(next);
};
if(d2 == ENDED) {
next.t2 = sch.t2;
try_done(ENDED, sch.ts3);
}
auto p = sch.t2->t.lower_bound({d2, -999});
while(p != sch.t2->t.end() && p->first.first == d2) {
int d3 = p->first.second;
if(sch.fin3 && d3 != ENDED) break; // we can break right away
auto r3 = get_abs_rule1(sch.ts3, d3);
next.t2 = p->second;
try_done(d3, r3);
p++;
}
};
next.t1 = sch.t1;
try_d3(ENDED, ENDED, sch.ts1, sch.ts2);
for(auto& p12: sch.t1->t) {
int d1 = p12.first.first;
int d2 = p12.first.second;
if(sch.fin1 && d1 != ENDED) break; /* we can break right away -- no more to find */
if(sch.fin2 && d2 != ENDED) continue; /* ... but here we cannot */
auto r1 = get_abs_rule1(sch.ts1, d1);
auto r2 = get_abs_rule1(sch.ts2, d2);
next.t1 = p12.second;
try_d3(d1, d2, r1, r2);
}
}
}
}
println(hlog, "composition queue = ", isize(q), " tdc = ", tie(tdc, tdc2));
}
void throw_identity_errors(const transducer& id, const vector<int>& cyc) {
@ -1052,11 +1096,14 @@ EX void find_multiple_interpretation() {
throw rulegen_failure("no multiple interpretation found");
}
EX int max_err_iter = 4;
EX void test_transducers() {
if(flags & w_skip_transducers) return;
autom.clear();
int iterations = 0;
int multiple_interpretations = 0;
int err_iter = 0;
while(true) {
next_iteration:
check_timeout();
@ -1067,10 +1114,20 @@ EX void test_transducers() {
struct searcher {
int ts;
vector<transducer_transitions*> pstates;
bool operator < (const searcher& s2) const { return tie(ts, pstates) < tie(s2.ts, s2.pstates); }
// bool operator < (const searcher& s2) const { return tie(ts, pstates) < tie(s2.ts, s2.pstates); }
bool operator == (const searcher& s2) const { return tie(ts, pstates) == tie(s2.ts, s2.pstates); }
};
set<searcher> in_queue;
struct searchhash {
size_t operator() (const searcher& s) const {
size_t res = hsh(s.ts);
// https://stackoverflow.com/questions/20511347/a-good-hash-function-for-a-vector
for(auto p: s.pstates) res ^= size_t(p) + 0x9e3779b9 + (res << 6) + (res >> 2);
return res;
}
};
std::unordered_set<searcher, searchhash> in_queue;
vector<searcher> q;
vector<int> parent_id;
vector<int> parent_dir;
@ -1090,7 +1147,8 @@ EX void test_transducers() {
searcher sch = searcher{ ts.tstate1, { &(autom[ts]) } };
enqueue(sch, -1, -1);
}
for(int i=0; i<isize(q); i++) {
auto process = [&] (int i) {
searcher sch = q[i];
int dirs = isize(treestates[sch.ts].rules);
@ -1101,7 +1159,9 @@ EX void test_transducers() {
for(auto v: sch.pstates) if(v->accepting_directions & (1<<dir)) qty++;
for(auto v: sch.pstates) for(auto& p: v->t) if(p.first.first == ENDED && (p.second->accepting_directions & (1<<dir))) qty++;
if(qty > 1) {
multiple_interpretations++;
// print_transducer(autom);
if(!(flags & w_r3_all_errors)) {
vstate vs;
vector<int> path1;
int at = build_vstate(vs, path1, parent_dir, parent_id, i, [&] (int i) { return q[i].ts; });
@ -1117,9 +1177,8 @@ EX void test_transducers() {
if(at == -1) break;
}
multiple_interpretations++;
// print_transducer(autom);
if(!(flags & w_r3_all_errors)) find_multiple_interpretation();
find_multiple_interpretation();
}
}
if(qty == 0) {
vstate vs;
@ -1171,11 +1230,15 @@ EX void test_transducers() {
next.pstates.resize(ip - next.pstates.begin());
enqueue(next, i, s);
}
}
};
for(int i=0; i<isize(q); i++) process(i);
if(changes) {
println(hlog, "changes = ", changes, " with ", isize(autom), " states");
goto next_iteration;
println(hlog, "changes = ", changes, " with ", isize(autom), " states, queue size = ", isize(q), ", add = ", isize(important)-impcount, " MI = ", multiple_interpretations);
if(isize(important) > impcount || multiple_interpretations) err_iter++;
if(err_iter < max_err_iter) goto next_iteration;
if(err_iter == max_err_iter) max_err_iter++;
}
if((flags & w_r3_all_errors) && isize(important) > impcount) throw rulegen_retry("errors found by transducers");
@ -1185,7 +1248,7 @@ EX void test_transducers() {
find_multiple_interpretation();
}
println(hlog, "transducers found successfully after ", iterations, " iterations, ", isize(autom), " states checked, queue size = ", isize(q));
println(hlog, "transducers found successfully after ", iterations, " iterations, ", isize(autom), " states checked, queue size = ", isize(q), " rmmemo size = ", isize(rmmemo));
vector<vector<transducer>> special(isize(t_origin));
for(int tid=0; tid<isize(t_origin); tid++) {
@ -1534,6 +1597,8 @@ EX void cleanup3() {
qroad_for.clear();
qroad_memo.clear();
possible_parents.clear();
rmmemo.clear();
max_err_iter = 4;
}
#if CAP_COMMANDLINE