// compute mAP/MeanRank rankings, for DHRG model and for general continuous distances

namespace dhrg {

ll rtally[MAXDIST];
int redgetally[MAXDIST];

vector<vector<int>> directed_edges;

void read_directed_edges(string fname) {
  fhstream g(fname, "rt");
  if(!g.f) {
    println(hlog, "Missing file: ", fname);
    exit(1);
    }
  println(hlog, "Reading directed edges...");
  directed_edges.clear();
  while(isize(directed_edges) <= N) directed_edges.emplace_back();
  while(true) {
    int i = rogueviz::readLabel(g), j = rogueviz::readLabel(g);
    if(i == -1 || j == -1) break;
    while(isize(directed_edges) <= i) directed_edges.emplace_back();
    directed_edges[i].emplace_back(j);
    }  
  }

int count_directed_edges() {
  int M = 0;
  for(int i=0; i<N; i++) M += isize(directed_edges[i]);
  return M;
  }

void tallydiredgesof(int i, int delta, mycell *mc) {
  for(auto j: directed_edges[i]) {
    whichedgetally[quickdist(mc, vertices[j], 0)] += delta;
    }
  }

void dhrg_ranks() {

  /*
  print(hlog, "check tally = ");
  for(int j=0; j<MAXDIST; j++)
    if(edgetally[j] || tally[j])
      print(hlog, j, ":", int(edgetally[j]), "/", int(tally[j]));
  println(hlog);
  */

  dynamicval<ll*> dt(whichtally, rtally);
  dynamicval<int*> det(whichedgetally, redgetally);

  ld meanrank = 0;
  ld meanrank_opti = 0;
  int tgood = 0;
  rtally[0]--; // do not count self
  ld maprank = 0;
  ld maprank_opti = 0;
  
  progressbar pb(N, "compute_ranks");
  for(int i=0; i<N; i++) {
    mycell *mc = vertices[i];
    tallydiredgesof(i, 1, mc);
    add_to_tally(mc, 1, 0);

    if(i < -10) {
      print(hlog, "tallies for i=", i, " =");
      for(int j=0; j<MAXDIST; j++)
        if(redgetally[j] || rtally[j])
          print(hlog, " ", j, ":", int(redgetally[j]), "/", int(rtally[j]));
      println(hlog);
      }

    // print(hlog, "LINE:");

    int pgood = 0;
    ld bad = 0;
    ld ap = 0;
    ld ap_opti = 0;
    ld pall = 0;
    // ld lastbad = 0;

    for(int j=0; j<MAXDIST; j++) {
      ld good = redgetally[j];
      ld all = rtally[j];
      ld err = all - good;

      /* for(int k=0; k<good; k++) {
        lastbad = bad;
        print(hlog, " ", pgood+bad+k+1);
        } */

      meanrank_opti += bad * good;
      bad += err / 2.;
      meanrank += bad * good;
      bad += err / 2.;

      for(int k=1; k<=good; k++) {
        ap_opti += (pgood+k) / (pall+k);
        }

      for(int k=0; k<good; k++) {
        pgood++, pall++;
        pall += err/2 / good;
        ap += pgood / pall;
        pall += err/2 / good;
        }
      if(!good) pall += err;

      }

    // if(lastbad > 30) print(hlog, " ** BAD");
    tgood += pgood;

    // print(hlog, " -> ", meanrank/(tgood+pgood), " (pgood ", pgood, ") (tgood ", tgood, ")");
    // println(hlog);

    if(pgood) maprank += ap / pgood;
    if(pgood) maprank_opti += ap_opti / pgood;
    tallydiredgesof(i, -1, mc);
    add_to_tally(mc, -1, 0);
    
    if(i < -10) {
      println(hlog, meanrank, "/", tgood, " ", ap, "/", pgood, " ", ap_opti, "/", pgood);
      }
    pb++;
    }

  rtally[0]++;
  print(hlog, "tallies for nothing =");
  for(int j=0; j<MAXDIST; j++)
    if(redgetally[j] || rtally[j])
      print(hlog, " ", j, ":", int(redgetally[j]), "/", int(rtally[j]));
  println(hlog);

  int tot_n = 0;
  for(int i=0; i<N; i++)
    if(isize(directed_edges[i]))
      tot_n++;

  println(hlog, "meanrank = ", meanrank / tgood, " MAP = ", maprank / tot_n, " meanrank_opti = ", meanrank_opti / tgood, " MAP_opti = ", maprank_opti / tot_n);
  }

void continuous_ranks(const distfun& df) {
  ld tot_ranks = 0, tot_rby = 0, tot_map = 0, tot_n = 0;

  if(1) {
    progressbar pb(N/threads, "continuous ranks");

    std::mutex lock; 
    parallelize(N, [&] (int a, int b) {
      ld ltot_ranks = 0, ltot_rby = 0, ltot_map = 0, ltot_n = 0;
      for(int i=a; i<b; i++) {
        int qty = isize(directed_edges[i]);
        if(!qty) continue;
        vector<pair<ld, int>> dists(N);
        // println(hlog, i, ": ", dists);
        for(int j=0; j<N; j++) dists[j] = { df(i, j), 0};

        for(auto e: directed_edges[i]) dists[e].second = 1;

/*      for(auto& d: dists) if(d.second == 0) d.first += 0.5;
        vector<int> ba(MAXDIST, 0), bb(MAXDIST, 0);
        for(auto& d: dists) { if(d.second == 1) ba[d.first]++; bb[d.first]++; } */

/*    bb[0]--; print(hlog, i, ": "); for(int d=0; d<MAXDIST; d++) if(bb[d]) print(hlog, d, " : ", ba[d],"/",bb[d], " ");
    println(hlog); */

        // dists[i].first -= 2;
        sort(dists.begin(), dists.end());

        vector<int> ranks;
        int seen = 0;
        int bad = 0;
        ld for_map = 0;
        // note: i itself is in first position
        for(int j=0; seen<qty; j++)
          if(dists[j].second) {
            ltot_ranks += bad;
            ranks.push_back(bad+seen);
            // if(bad+seen+1 <= qty) for_map++; // 
            for_map += (seen+1.) / (bad+seen);
            // printf("%d/%d ", seen+1, bad+seen);
            seen++;
            }
          else
            bad++;
        if(a == 0) pb++;
        ltot_rby += qty;
        ltot_map += for_map / qty;
// println(hlog, "contribution: ", for_map / qty);
        ltot_n++;
        }
      std::unique_lock<std::mutex> lk(lock);
      tot_rby += ltot_rby;
      tot_map += ltot_map;
      tot_ranks += ltot_ranks;
      tot_n += ltot_n;
      return 0;
      });
    }
  println(hlog, "MeanRank = ", tot_ranks / tot_rby, " MAP = ", tot_map / tot_n);
  println(hlog, "data: ", tie(tot_rby, tot_map, tot_ranks, tot_n, N));
  }


}
