From 951566399e157107f077230e9b23e7009839a25f Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 1 Sep 2017 22:13:41 +0200 Subject: [PATCH] further improvements to Kohonen --- hyper.h | 1 + kohonen.cpp | 357 ++++++++++++++++++++++++++++++++++++++++++++------- rogueviz.cpp | 21 ++- 3 files changed, 332 insertions(+), 47 deletions(-) diff --git a/hyper.h b/hyper.h index f56e750b..15330ffc 100644 --- a/hyper.h +++ b/hyper.h @@ -1524,6 +1524,7 @@ void addauraspecial(const hyperpoint& h, int col, int dir); void drawBug(const cellwalker& cw, int col); void mainloop(); +void mainloopiter(); extern bool showstartmenu; void selectLanguageScreen(); diff --git a/kohonen.cpp b/kohonen.cpp index cb441ff1..896d09bb 100644 --- a/kohonen.cpp +++ b/kohonen.cpp @@ -30,6 +30,8 @@ struct neuron { int samples, csample, bestsample; }; +vector colnames; + kohvec weights; vector net; @@ -94,10 +96,12 @@ void loadsamples(const char *fname) { bigbreak: fclose(f); samples = size(data); - normalize(); + normalize(); + colnames.resize(cols); + for(int i=0; i listing; for(neuron& n: net) switch(c) { case -4: - listing.push_back(n.samples); + listing.push_back(log(5+n.samples)); break; case -3: @@ -477,6 +481,42 @@ void uninit(int initto) { if(inited > initto) inited = initto; } +void showsample(int id) { + for(int ii: samples_shown) + if(ii == id) + return; + int i = vdata.size(); + samples_shown.push_back(id); + vdata.emplace_back(); + auto& v = vdata.back(); + v.name = data[id].name; + v.cp = dftcolor; + createViz(i, cwt.c, Id); + v.m->store(); + } + +void showsample(string s) { + if(s == "") return; + for(int i=0; i samplesbak; + for(auto& n: net) + if(n.samples) + showsample(n.bestsample); + analyze(); + for(auto& n: net) n.samples = 0; + for(int i=0; isamples++; + } + void sominit(int initto) { if(inited < 1 && initto >= 1) { @@ -563,19 +603,151 @@ void describe(cell *c) { if(cmode & sm::HELP) return; neuron *n = getNeuronSlow(c); if(!n) return; - help += "cell number: " + its(neuronId(*n)) + "\n"; + help += "cell number: " + its(neuronId(*n)) + " (" + its(n->samples) + ")\n"; help += "parameters:"; for(int k=0; knet[k]); help += ", u-matrix = " + fts(n->udist); help += "\n"; - int qty = 0; - for(int s=0; s> v; + for(int s=0; snet, data[s].val), s); + random_shuffle(v.begin(), v.end()); + sort(v.begin(), v.end(), [] (auto a, auto b) { return a.first < b.first; }); + + for(int i=0; i= 20) break; } } +namespace levelline { + + struct levelline { + int column, qty; + unsigned int color; + vector values; + bool modified; + }; + + vector levellines; + + bool on; + + void create() { + int xlalpha = int(pow(ld(.5), ggamma) * 255); + for(int i=0; i sample; + for(int j=0; j<=1024; j++) sample.push_back(data[hrand(samples)].val[lv.column]); + sort(sample.begin(), sample.end()); + lv.values.clear(); + lv.values.push_back(-1e10); + for(int j=0; j<=1024; j+=1024 >> (lv.qty)) lv.values.push_back(sample[j]); + lv.values.push_back(1e10); + } + } + + void draw() { + if(!on) return; + for(auto& g: gmatrix) { + cell *c1 = g.first; + transmatrix T = g.second; + neuron *n1 = getNeuron(c1); + if(!n1) continue; + for(int i=0; itype; i++) { + cell *c2 = c1->mov[i]; + if(!c2) continue; + cell *c3 = c1->mov[i ? i-1 : c1->type-1]; + if(!c3) continue; + + if(!gmatrix.count(c2)) continue; + if(!gmatrix.count(c3)) continue; + double d2 = hdist(tC0(T), tC0(gmatrix[c2])); + double d3 = hdist(tC0(T), tC0(gmatrix[c3])); + + neuron *n2 = getNeuron(c2); + if(!n2) continue; + neuron *n3 = getNeuron(c3); + if(!n3) continue; + + for(auto& l: levellines) { + auto val1 = n1->net[l.column]; + auto val2 = n2->net[l.column]; + auto val3 = n3->net[l.column]; + auto v1 = lower_bound(l.values.begin(), l.values.end(), val1); + auto v2 = lower_bound(l.values.begin(), l.values.end(), val2); + auto v3 = lower_bound(l.values.begin(), l.values.end(), val3); + auto draw = [&] () { + auto vmid = *v1; + queueline( + tC0(T * ddspin(c1,i) * xpush(d2 * (vmid-val1) / (val2-val1))), + tC0(T * ddspin(c1,i-1) * xpush(d3 * (vmid-val1) / (val3-val1))), + l.color); + }; + while(v1 < v2 && v1 < v3) { + draw(); + v1++; + } + while(v1 > v2 && v1 > v3) { + v1--; + draw(); + } + } + } + } + setindex(false); + } + + void show() { + if(levellines.size() == 0) create(); + gamescreen(0); + cmode = vid.xres > vid.yres * 1.4 ? sm::SIDE : 0; + dialog::init("level lines"); + char nx = 'a'; + for(auto &l : levellines) { + dialog::addSelItem(colnames[l.column], its(l.qty), nx++); + dialog::lastItem().colorv = l.color >> 8; + } + dialog::addItem("exit menu", '0'); + dialog::addItem("shift+letter to change color", 0); + dialog::display(); + keyhandler = [] (int sym, int uni) { + dialog::handleNavigation(sym, uni); + if(uni >= 'a' && uni - 'a' + size(levellines)) { + auto& l = levellines[uni - 'a']; + dialog::editNumber(l.qty, 0, 10, 1, 0, colnames[l.column], + XLAT("Controls the number of level lines.")); + dialog::reaction = [&l] () { + l.modified = true; + build(); + }; + } + else if(uni >= 'A' && uni - 'A' + size(levellines)) { + auto& l = levellines[uni - 'A']; + dialog::openColorDialog(l.color, NULL); + } + else if(doexiton(sym, uni)) popScreen(); + }; + } + + + } + void ksave(const char *fname) { sominit(1); FILE *f = fopen(fname, "wt"); @@ -586,7 +758,7 @@ void ksave(const char *fname) { fprintf(f, "%d %d\n", cells, t); for(neuron& n: net) { for(int k=0; k= lastprogress + (noGUI ? 500 : 100)) { + if(noGUI) + printf("%s\n", s.c_str()); + else { + clearMessages(); + addMessage(s); + mainloopiter(); + } + lastprogress = SDL_GetTicks(); + } + } + +void kclassify(const char *fname_classify) { sominit(1); vector bdiffs(samples, 1e20); @@ -646,9 +856,10 @@ void kclassify2(const char *fname_classify, const char *fname_samples) { double diff = vnorm(net[n].net, data[s].val); if(diff < bdiffs[s]) bdiffs[s] = diff, bids[s] = n, whowon[s] = &net[n]; } - if(s % 1000000 == 999999) printf("%d/%d\n", s, samples); + if(!(s % 128)) + progress("Classifying: " + its(s) + "/" + its(samples)); } - + vector bdiffn(cells, 1e20); printf("Finding samples...\n"); @@ -673,30 +884,55 @@ void kclassify2(const char *fname_classify, const char *fname_samples) { fclose(f); } } + coloring(); + } +void klistsamples(const char *fname_samples, bool best, bool colorformat) { if(fname_samples != NULL) { - printf("Listing best samples...\n"); + printf("Listing samples...\n"); FILE *f = fopen(fname_samples, "wt"); if(!f) { printf("Failed to open file\n"); } else { - fprintf(f, "%d\n", cols); - for(int n=0; n i) kohonen::step(); + shift(); while(t > i) { + if(t % 128 == 0) progress("Steps left: " + its(t)); + kohonen::step(); + } } else if(argis("-somstop")) { t = 0; @@ -809,7 +1054,10 @@ int readArgs() { noshow = true; } else if(argis("-somfinish")) { - while(!finished()) kohonen::step(); + while(!finished()) { + kohonen::step(); + if(t % 128 == 0) progress("Steps left: " + its(t)); + } } // #5 save data, classify etc. @@ -817,22 +1065,43 @@ int readArgs() { PHASE(3); shift(); kohonen::ksave(args()); } + else if(argis("-somsavew")) { + PHASE(3); + shift(); kohonen::ksavew(args()); + } + else if(argis("-somloadw")) { + PHASE(3); + shift(); kohonen::kloadw(args()); + } else if(argis("-somclassify")) { PHASE(3); shift(); kohonen::kclassify(args()); } - else if(argis("-somclassify2")) { + else if(argis("-somlistshown")) { PHASE(3); - shift(); const char *f1 = args(); - shift(); const char *f2 = args(); - kohonen::kclassify2(f1, f2); + shift(); kohonen::klistsamples(args(), false, false); + } + else if(argis("-somlistbest")) { + PHASE(3); + shift(); kohonen::klistsamples(args(), true, false); + } + else if(argis("-somlistbestc")) { + PHASE(3); + shift(); kohonen::klistsamples(args(), true, true); + } + else if(argis("-somndist")) { + PHASE(3); + shift(); kohonen::neurondisttable(args()); + } + else if(argis("-somshowbest")) { + showbestsamples(); } else return 1; return 0; } -auto hooks = addHook(hooks_args, 100, readArgs); +auto hooks = addHook(hooks_args, 100, readArgs) + addHook(hooks_frame, 50, levelline::draw); } void mark(cell *c) { diff --git a/rogueviz.cpp b/rogueviz.cpp index f3c19a72..c85fc8a7 100644 --- a/rogueviz.cpp +++ b/rogueviz.cpp @@ -29,6 +29,8 @@ bool specialmark = false; bool rog3 = false; +ld ggamma = .5; + string fname; // const char *fname; @@ -1027,8 +1029,6 @@ void queuedisk(const transmatrix& V, const colorpair& cp, bool legend) { if(cp.shade == 'm') queuepoly(V, shDiskM, cp.color2); } -ld ggamma = .5; - void drawVertex(const transmatrix &V, cell *c, shmup::monster *m) { if(m->dead) return; int i = m->pid; @@ -1292,7 +1292,16 @@ void readcolor(const char *cfname) { colorpair x; int c2 = fgetc(f); - if(c2 == '=') { + if(kohonen::samples && c2 == '+') { + kohonen::showsample(lab); + c2 = fgetc(f); + if(c2 == 10 || c2 == 13) continue; + } + if(c2 == '#') { + while(c2 != 10 && c2 != 13 && c2 != -1) c2 = fgetc(f); + continue; + } + else if(c2 == '=') { string lab2 = ""; while(true) { int c = fgetc(f); @@ -1326,6 +1335,12 @@ void readcolor(const char *cfname) { vdata[i].cp = x; } } + else if(kohonen::samples) { + for(int i=0; i