mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-17 18:54:48 +00:00
rulegen3:: more improvements
This commit is contained in:
parent
a441ab474f
commit
80c3dfcd34
149
rulegen3.cpp
149
rulegen3.cpp
@ -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, 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)); }
|
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;
|
transducer autom;
|
||||||
int comp_step;
|
int comp_step;
|
||||||
@ -546,7 +558,15 @@ tcell* get_move(tcell *c, int dir) {
|
|||||||
return c->cmove(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) {
|
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(dir1 != ENDED) t = rev_move(t, dir1);
|
||||||
if(dir2 != ENDED) {
|
if(dir2 != ENDED) {
|
||||||
t = t->cmove(dir2);
|
t = t->cmove(dir2);
|
||||||
@ -555,7 +575,7 @@ tcell *rev_move2(tcell *t, int dir1, int dir2) {
|
|||||||
}
|
}
|
||||||
twalker tw = t; get_parent_dir(tw);
|
twalker tw = t; get_parent_dir(tw);
|
||||||
if(t->dist && t->parent_dir == MYSTERY) throw rulegen_failure("no parent_dir assigned after rev_move2!");
|
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) {
|
vector<int> desc(tcell *t) {
|
||||||
@ -664,10 +684,20 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul
|
|||||||
transducer_transitions *ires;
|
transducer_transitions *ires;
|
||||||
const transducer_transitions *t1;
|
const transducer_transitions *t1;
|
||||||
const transducer_transitions *t2;
|
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;
|
vector<searcher> q;
|
||||||
auto enqueue = [&] (const searcher& s) {
|
auto enqueue = [&] (const searcher& s) {
|
||||||
if(in_queue.count(s)) return;
|
if(in_queue.count(s)) return;
|
||||||
@ -685,38 +715,20 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul
|
|||||||
enqueue(sch);
|
enqueue(sch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tdc = 0, tdc2 = 0;
|
||||||
|
|
||||||
for(int i=0; i<isize(q); i++) {
|
for(int i=0; i<isize(q); i++) {
|
||||||
auto sch = q[i];
|
auto sch = q[i];
|
||||||
if(sch.t1->accepting_directions && sch.t2->accepting_directions)
|
if(sch.t1->accepting_directions && sch.t2->accepting_directions)
|
||||||
sch.ires->accepting_directions = 1;
|
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;
|
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.ts1 = r1; next.fin1 = d1 == ENDED;
|
||||||
next.ts2 = r2; next.fin2 = d2 == ENDED;
|
next.ts2 = r2; next.fin2 = d2 == ENDED;
|
||||||
next.ts3 = r3; next.fin3 = d3 == 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]);
|
next.ires = sch.ires->t[{d1, d3}] = &(result[nstate_key]);
|
||||||
|
|
||||||
enqueue(next);
|
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) {
|
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");
|
throw rulegen_failure("no multiple interpretation found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EX int max_err_iter = 4;
|
||||||
|
|
||||||
EX void test_transducers() {
|
EX void test_transducers() {
|
||||||
if(flags & w_skip_transducers) return;
|
if(flags & w_skip_transducers) return;
|
||||||
autom.clear();
|
autom.clear();
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
int multiple_interpretations = 0;
|
int multiple_interpretations = 0;
|
||||||
|
int err_iter = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
next_iteration:
|
next_iteration:
|
||||||
check_timeout();
|
check_timeout();
|
||||||
@ -1067,10 +1114,20 @@ EX void test_transducers() {
|
|||||||
struct searcher {
|
struct searcher {
|
||||||
int ts;
|
int ts;
|
||||||
vector<transducer_transitions*> pstates;
|
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<searcher> q;
|
||||||
vector<int> parent_id;
|
vector<int> parent_id;
|
||||||
vector<int> parent_dir;
|
vector<int> parent_dir;
|
||||||
@ -1090,7 +1147,8 @@ EX void test_transducers() {
|
|||||||
searcher sch = searcher{ ts.tstate1, { &(autom[ts]) } };
|
searcher sch = searcher{ ts.tstate1, { &(autom[ts]) } };
|
||||||
enqueue(sch, -1, -1);
|
enqueue(sch, -1, -1);
|
||||||
}
|
}
|
||||||
for(int i=0; i<isize(q); i++) {
|
|
||||||
|
auto process = [&] (int i) {
|
||||||
searcher sch = q[i];
|
searcher sch = q[i];
|
||||||
|
|
||||||
int dirs = isize(treestates[sch.ts].rules);
|
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) 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++;
|
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) {
|
if(qty > 1) {
|
||||||
|
multiple_interpretations++;
|
||||||
|
// print_transducer(autom);
|
||||||
|
if(!(flags & w_r3_all_errors)) {
|
||||||
vstate vs;
|
vstate vs;
|
||||||
vector<int> path1;
|
vector<int> path1;
|
||||||
int at = build_vstate(vs, path1, parent_dir, parent_id, i, [&] (int i) { return q[i].ts; });
|
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;
|
if(at == -1) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
multiple_interpretations++;
|
find_multiple_interpretation();
|
||||||
// print_transducer(autom);
|
}
|
||||||
if(!(flags & w_r3_all_errors)) find_multiple_interpretation();
|
|
||||||
}
|
}
|
||||||
if(qty == 0) {
|
if(qty == 0) {
|
||||||
vstate vs;
|
vstate vs;
|
||||||
@ -1171,11 +1230,15 @@ EX void test_transducers() {
|
|||||||
next.pstates.resize(ip - next.pstates.begin());
|
next.pstates.resize(ip - next.pstates.begin());
|
||||||
enqueue(next, i, s);
|
enqueue(next, i, s);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
for(int i=0; i<isize(q); i++) process(i);
|
||||||
|
|
||||||
if(changes) {
|
if(changes) {
|
||||||
println(hlog, "changes = ", changes, " with ", isize(autom), " states");
|
println(hlog, "changes = ", changes, " with ", isize(autom), " states, queue size = ", isize(q), ", add = ", isize(important)-impcount, " MI = ", multiple_interpretations);
|
||||||
goto next_iteration;
|
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");
|
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();
|
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));
|
vector<vector<transducer>> special(isize(t_origin));
|
||||||
for(int tid=0; tid<isize(t_origin); tid++) {
|
for(int tid=0; tid<isize(t_origin); tid++) {
|
||||||
@ -1534,6 +1597,8 @@ EX void cleanup3() {
|
|||||||
qroad_for.clear();
|
qroad_for.clear();
|
||||||
qroad_memo.clear();
|
qroad_memo.clear();
|
||||||
possible_parents.clear();
|
possible_parents.clear();
|
||||||
|
rmmemo.clear();
|
||||||
|
max_err_iter = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CAP_COMMANDLINE
|
#if CAP_COMMANDLINE
|
||||||
|
Loading…
Reference in New Issue
Block a user