1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-27 14:37:16 +00:00
hyperrogue/rogueviz/sag/data.cpp
2024-08-21 19:24:04 +02:00

424 lines
10 KiB
C++

// RogueViz -- SAG embedder: data manager
// Copyright (C) 2011-24 Zeno Rogue, see 'hyper.cpp' for details
#include "../rogueviz.h"
namespace rogueviz {
namespace sag {
using namespace cells;
edgetype *sag_edge;
/** if this is true, no nodes are allowed to be on the same subcell */
bool allow_doubles = false;
/** node i is on sagcells[sagid[i]] */
vector<int> sagid;
/** what node is on sagcells[i] (need loglik_repeat to be off) */
vector<int> sagnode;
/* separate hubs -- only for smClosest */
ld hub_penalty;
string hub_filename;
vector<int> hubval;
vector<edgeinfo> sagedges;
vector<vector<int>> edges_yes, edges_no;
vector<vector<pair<int, double>>> edge_weights;
vector<bool> fixed_position;
ld edgepower=1, edgemul=1;
void init();
void compute_cost();
void prepare_graph() {
int DN = isize(sagid);
println(hlog, "prepare_graph with DN = ", DN);
set<pair<int, int>> alledges;
for(auto e: sagedges) {
if(e.i == e.j) continue;
alledges.emplace(e.i, e.j);
alledges.emplace(e.j, e.i);
}
edges_yes.clear(); edges_yes.resize(DN);
edges_no.clear(); edges_no.resize(DN);
fixed_position.clear(); fixed_position.resize(DN);
for(int i=0; i<DN; i++) for(int j=0; j<DN; j++) if(i != j) {
if(alledges.count({i, j}))
edges_yes[i].push_back(j);
else
edges_no[i].push_back(j);
}
edge_weights.clear(); edge_weights.resize(DN);
for(auto& e: sagedges) {
if(e.i == e.j) continue;
e.weight2 = pow((double) e.weight, (double) edgepower) * edgemul;
edge_weights[e.i].emplace_back(e.j, e.weight2);
edge_weights[e.j].emplace_back(e.i, e.weight2);
}
sagnode.clear();
sagnode.resize(isize(sagcells), -1);
for(int i=0; i<DN; i++)
sagnode[sagid[i]] = i;
compute_cost();
}
void set_inverse();
void place_correctly() {
int DN = isize(sagid);
vector<int> qon(isize(sagcells), 0);
for(int i=0; i<DN; i++) qon[sagid[i]]++;
vector<int> qsf(isize(sagcells), 0);
ld rad = .25 * cgi.scalefactor;
if(isize(subcell_points) > 1) rad /= pow(isize(subcell_points), WDIM);
for(int i=0; i<DN; i++) {
int ci = sag::sagid[i];
vdata[i].m->base = sagcells[ci].first;
vdata[i].m->at = Id;
if(allow_doubles) vdata[i].m->at =
spin(TAU*(qsf[ci]++) / qon[ci]) * xpush(rad * (qon[ci]-1) / qon[ci]);
if(isize(subcell_points) > 1)
vdata[i].m->at = rgpushxto0(subcell_points[sagcells[ci].second]) * vdata[i].m->at;
}
}
bool visualization_active;
void forgetedges(int id) {
for(int i=0; i<isize(vdata[id].edges); i++)
vdata[id].edges[i].second->orig = NULL;
}
void create_viz() {
if(distance_only) return;
int DN = isize(sagid);
bool vact = state & SS_GRAPH;
state |= SS_GRAPH;
if(!vact) for(int i=0; i<DN; i++) vdata[i].data = 0;
if(!vact) for(auto& e: sagedges) addedge0(e.i, e.j, &e);
if(sagcells[0].first == nullptr) return;
if(vact) for(int i=0; i<DN; i++) forgetedges(i);
if(!vact) for(int i=0; i<DN; i++) {
vertexdata& vd = vdata[i];
vd.cp = colorpair(dftcolor);
rogueviz::createViz(i, sagcells[sagid[i]].first, Id);
}
place_correctly();
if(!vact) storeall();
if(vact) shmup::fixStorage();
set_inverse();
vact = true;
}
/** save the SAG solution (sagid) */
void save_sag_solution(const string& fname) {
if(!(state & SS_DATA)) throw hr_exception("save_sag_solution with no data");
FILE *f = fopen(fname.c_str(), "wt");
if(!f) throw hr_exception("failed to save SAG solution");
for(int i=0; i<isize(sagid); i++)
fprintf(f, "%s;%d\n", vdata[i].name.c_str(), sagid[i]);
fclose(f);
}
/** load the SAG solution (sagid) */
void load_sag_solution(const string& fname) {
if(!(state & SS_DATA)) throw hr_exception("load_sag_solution with no data");
printf("Loading the sag from: %s\n", fname.c_str());
FILE *sf = fopen(fname.c_str(), "rt");
if(!sf) throw hr_exception("failed to load SAG solution");
int SN = isize(sagcells);
if(sf) while(true) {
string lab;
while(true) {
int c = fgetc(sf);
if(c == EOF) goto afterload;
else if(c == ',' || c == ';') break;
else if(rv_ignore(c)) ;
else lab += c;
}
int sid = -1;
int err = fscanf(sf, "%d", &sid);
if(sid < 0 || sid >= SN || err < 1) sid = -1;
if(!labeler.count(lab)) {
printf("unknown vertex: %s\n", lab.c_str());
}
else {
int id = getid(lab);
sagid[id] = sid;
}
}
afterload:
if(sf) fclose(sf);
prepare_graph();
create_viz();
}
void load_sag_solution_basic(const string& fname) {
if(!(state & SS_DATA)) throw hr_exception("load_sag_solution_basic with no data");
FILE *f = fopen(fname.c_str(), "rt");
for(auto& i: sagid) if(fscanf(f, "%d", &i) < 1) throw hr_exception("read error in load_sag_solution_basic");
fclose(f);
println(hlog, "loaded sagid = ", sagid);
prepare_graph();
create_viz();
}
void after_data() {
state |= SS_DATA;
init_snake_if_needed();
int DN = isize(vdata);
int SN = isize(sagcells);
if(SN < DN) {
println(hlog, "SN = ", SN, " DN = ", DN);
throw hr_exception("not enough cells for SAG");
}
sagid.resize(DN);
for(int i=0; i<DN; i++) sagid[i] = i;
prepare_graph();
create_viz();
}
/** load all the edges */
void read_weighted(const char *fname) {
if(state & SS_DATA) return;
state |= SS_WEIGHTED;
init_cells();
maxweight = 0;
fhstream f(fname, "rt");
if(!f.f) throw hr_exception("readsag_weighted: failed to open");
while(!feof(f.f)) {
string l1, l2;
while(true) {
int c = fgetc(f.f);
if(c == EOF) goto after;
else if(c == ';') break;
else if(rv_ignore(c)) ;
else l1 += c;
}
while(true) {
int c = fgetc(f.f);
if(c == EOF) goto after;
else if(c == ';') break;
else if(rv_ignore(c)) ;
else l2 += c;
}
ld wei;
if(!scan(f, wei)) continue;
edgeinfo ei(sag_edge);
ei.i = getid(l1);
ei.j = getid(l2);
ei.weight = wei;
sagedges.push_back(ei);
}
after:
println(hlog, "weighted graph ", fname, " read successfully");
after_data();
}
/** load edges, in */
void read_unweighted(const char *fname) {
if(state & SS_DATA) return;
init_cells();
fhstream f(fname, "rt");
if(!f.f) throw hr_exception("readsag_weighted: failed to open");
scanline(f);
set<pair<int, int> > edges;
int all = 0, good = 0;
while(!feof(f.f)) {
string l1 = scan<string>(f);
string l2 = scan<string>(f);
if(l1 == "") continue;
if(l2 == "") continue;
edgeinfo ei(sag_edge);
ei.i = getid(l1);
ei.j = getid(l2);
if(ei.i > ei.j) swap(ei.i, ei.j);
all++;
if(edges.count({ei.i, ei.j})) continue;
good++;
edges.emplace(ei.i, ei.j);
ei.weight = 1;
sagedges.push_back(ei);
}
println(hlog, "unweighted graph ", fname, " read successfully");
println(hlog, "N = ", isize(vdata), " edges = ", good, "/", all);
after_data();
}
void read_hubs(const string& fname) {
if(!(state & SS_DATA)) throw hr_exception("read_hubs with no data");
hubval.resize(isize(vdata), -1);
fhstream f(fname, "rt");
if(!f.f) { printf("Failed to open hub file: %s\n", fname.c_str()); exit(1); }
println(hlog, "loading hubs: ", fname);
while(!feof(f.f)) {
string l1, l2;
while(true) {
int c = fgetc(f.f);
if(c == EOF) return;
else if(c == ';') break;
else if(rv_ignore(c)) ;
else l1 += c;
}
while(true) {
int c = fgetc(f.f);
if(c == EOF) return;
else if(c == ';') return;
else if(rv_ignore(c)) break;
else l2 += c;
}
if(!id_known(l1)) {
printf("label unknown: %s\n", l1.c_str());
exit(1);
}
hubval[getid(l1)] = atoi(l2.c_str());
}
}
void generate_fake_data(int n, int m) {
if(state & SS_DATA) return;
init_cells();
state |= SS_WEIGHTED;
sagid.resize(n);
for(int i=0; i<n; i++) sagid[i] = i;
hrandom_shuffle(sagid);
if(m > n || m < 0) throw hr_exception("generate_fake_data parameters incorrect");
sagid.resize(m);
int DN = isize(sagid);
vdata.resize(DN);
for(int i=0; i<DN; i++)
vdata[i].name = its(i) + "@" + its(sagid[i]);
sag_edge = add_edgetype("SAG edge");
for(int i=0; i<DN; i++)
for(int j=i+1; j<DN; j++) {
edgeinfo ei(sag_edge);
ei.i = i;
ei.j = j;
ei.weight = 1. / sagdist[sagid[i]][sagid[j]];
sagedges.push_back(ei);
}
after_data();
for(int i=0; i<DN; i++) {
color_t col = ccolor::formula(sagcells[sagid[i]].first);
col <<= 8;
col |= 0xFF;
vdata[i].cp.color1 = vdata[i].cp.color2 = col;
}
}
int data_read_args() {
#if CAP_COMMANDLINE
using namespace arg;
if(0) ;
else if(argis("-sagmin")) {
auto& ed = sag_edge ? *sag_edge : default_edgetype;
shift_arg_formula(ed.visible_from);
ed.visible_from_hi = ed.visible_from;
}
else if(argis("-sagminhi")) {
auto& ed = sag_edge ? *sag_edge : default_edgetype;
shift_arg_formula(ed.visible_from_hi);
}
else if(argis("-sag-edgepower")) {
shift_arg_formula(sag::edgepower);
shift_arg_formula(sag::edgemul);
}
else if(argis("-sag-weighted")) {
PHASE(3);
shift(); sag::read_weighted(argcs());
}
else if(argis("-sag-unweighted")) {
PHASE(3);
shift(); sag::read_unweighted(argcs());
}
else if(argis("-saghubs")) {
PHASE(3);
shift_arg_formula(sag::hub_penalty);
shift(); sag::read_hubs(argcs());
}
else if(argis("-sag-generate")) {
PHASE(3);
shift(); int n = argi();
shift(); int m = argi();
sag::generate_fake_data(n, m);
}
// (3) load the initial positioning
else if(argis("-sag-load-sol")) {
PHASE(3); shift(); sag::load_sag_solution(args());
}
else if(argis("-sag-load-solution")) {
PHASE(3); shift(); sag::load_sag_solution_basic(args());
}
else if(argis("-sag-save-sol")) {
PHASE(3); shift(); sag::save_sag_solution(args());
}
else if(argis("-sag-fix")) {
shift(); int id = getid(args());
if(id >= isize(sagid)) throw hr_exception("bad id in -sag-fix");
fixed_position[id] = true;
}
else if(argis("-sag-move-to")) {
shift(); int sid1 = getid(args());
if(sid1 < 0 || sid1 >= isize(sagid)) throw hr_exception("bad id in -sag-move-to");
shift(); int t2 = argi();
if(t2 < 0 || t2 >= isize(sagnode)) throw hr_exception("bad id in -sag-move-to");
int sid2 = sagid[t2];
int t1 = allow_doubles ? -1 : sagnode[sid1];
sagnode[sid1] = t2; sagid[t2] = sid1;
if(sid2 >= 0) sagnode[sid2] = t1; sagid[t1] = sid2;
compute_cost();
create_viz();
}
else return 1;
#endif
return 0;
}
int ahdata = addHook(hooks_args, 100, data_read_args);
}
}