diff --git a/rulegen3.cpp b/rulegen3.cpp index 5448c4a2..ac1d2300 100644 --- a/rulegen3.cpp +++ b/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, const transducer_state& s) { print(hs, "S", tie(s.tstate1, s.tstate2, s.relation)); } -using transducer = map; +template size_t hsh(T t) { return std::hash()(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; + +using transducer = std::unordered_map; 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& tu) const { return hsh(get<0>(tu)) + (hsh(get<1>(tu)) << 8) + (hsh(get<2>(tu)) << 16); } + }; + +std::unordered_map, 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 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 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 in_queue; vector q; auto enqueue = [&] (const searcher& s) { if(in_queue.count(s)) return; @@ -684,54 +714,68 @@ void compose_with(const transducer& tr, const transducer& dir, transducer& resul searcher sch = searcher{ ts.tstate1, ts.tstate1, ts.tstate1, false, false, false, t.at, &(result[ts]), &(tr.at(ts)), &(dir.at(ts)) }; enqueue(sch); } + + int tdc = 0, tdc2 = 0; for(int i=0; iaccepting_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; d1t.count({d1, d2})) continue; - next.t1 = sch.t1->t.at({d1, d2}); - } - for(int d3=ENDED; d3t.count({d2, d3})) continue; - next.t2 = sch.t2->t.at({d2, d3}); - } + + auto try_d3 = [&] (int d1, int d2, int r1, int r2) { + tdc++; - next.ts1 = r1; next.fin1 = d1 == ENDED; - next.ts2 = r2; next.fin2 = d2 == ENDED; - next.ts3 = r3; next.fin3 = d3 == ENDED; - next.tat = rev_move2(sch.tat, d1, d3); - auto nstate_key = transducer_state { next.ts1, next.ts3, next.tat }; + 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; + next.tat = rev_move2(sch.tat, d1, d3); + auto nstate_key = transducer_state { next.ts1, next.ts3, next.tat }; - next.ires = sch.ires; - if(d1 != ENDED || d3 != ENDED) - next.ires = sch.ires->t[{d1, d3}] = &(result[nstate_key]); + next.ires = sch.ires; + if(d1 != ENDED || d3 != ENDED) + 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& 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 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 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 in_queue; vector q; vector parent_id; vector 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; iaccepting_directions & (1<t) if(p.first.first == ENDED && (p.second->accepting_directions & (1< 1) { - - vstate vs; - vector path1; - int at = build_vstate(vs, path1, parent_dir, parent_id, i, [&] (int i) { return q[i].ts; }); - println(hlog, "after path = ", path1, " got multiple interpretation"); - for(auto v: sch.pstates) if(v->accepting_directions & (1<t) if(p.first.first == ENDED && (p.second->accepting_directions & (1<accepting_directions & (1<t) if(p.first.first == ENDED && (p.second->accepting_directions & (1<