/*
  Copyright(C) 2007-2012 National Institute of Information and Communications Technology
*/

/*
  svmtools
  Multiclass classification program
*/


#include <stdio.h>
#include <stdlib.h>
#include "exception.h"
#include "svm_common.h"
#include "svm_mc.h"


int main(int argc, char **argv) {
  int i;
  char *exmfile, *mcmdlfile, *outfile;
  FILE *fp;
  SVM_EXM *exm;
  SVM_MC_MDL *mcmdl;
  int cor;
  int *cap, *sys, *gld;
  int count;
  int sum_cap, sum_sys, sum_gld;
  double sum_r, sum_p, sum_f;
  double r_mac, p_mac, f_mac, r_mic, p_mic, f_mic;

  /* 引数の処理 */
  if (argc != 3 && argc != 4) {
    fprintf(stderr, "usage: %s <example file> <multiclass model file> [<output file>]\n", argv[0]);
    return 1;
  }
  exmfile = argv[1];
  mcmdlfile = argv[2];
  outfile = (argc == 4) ? argv[3] : NULL;

  /* テストデータの読み込み */
  fprintf(stderr, "Reading the example file... ");
  fp = fopen(exmfile, "rt");
  exception(fp == NULL, "cannot open the example file '%s'", exmfile);
  exm = svm_readexm(fp);
  exception(exm == NULL, "cannot read the example file '%s'", exmfile);
  fclose(fp);
  fprintf(stderr, "done (%d examples).\n", exm->num);

  /* モデルデータの読み込み */
  fprintf(stderr, "Reading the model file... ");
  fp = fopen(mcmdlfile, "rt");
  exception(fp == NULL, "cannot open the model file '%s'", mcmdlfile);
  mcmdl = svm_mc_readmdl(fp);
  exception(mcmdl == NULL, "cannot read the model file '%s'", mcmdlfile);
  fclose(fp);
  fprintf(stderr, "done (method=%d, class=%d).\n", mcmdl->method, mcmdl->class);

  /* output fileのopen */
  if (outfile != NULL) {
    fp = fopen(outfile, "wt");
    exception(fp == NULL, "cannot open the output file '%s'", outfile);
  } else {
    fp = NULL;
  }

  /* 分類 */
  cap = smalloc(sizeof(int) * mcmdl->class);
  sys = smalloc(sizeof(int) * mcmdl->class);
  gld = smalloc(sizeof(int) * mcmdl->class);
  for (i = 0; i < mcmdl->class; i++) cap[i] = sys[i] = gld[i] = 0;
  cor = 0;
  for (i = 0, count = 1; i < exm->num; i++) {
    int c;

    c = svm_mc_decision(mcmdl, exm->sv[i]);
    if (outfile != NULL) fprintf(fp, "%d\n", c);
    if (exm->label[i] == c) {
      cap[c]++;
      cor++;
    }
    sys[c]++;
    gld[exm->label[i]]++;

    if (i + 1 == count) {
      fprintf(stderr, "%d ", i + 1);
      count *= 10;
    }
  }
  fprintf(stderr, "done.\n");
  if (outfile != NULL) fclose(fp);

  /* 結果表示 */
  printf("Accuracy:  %6.2f%%(%6d/%6d)\n", (exm->num > 0) ? (double)cor / exm->num * 100.0 : 0.0, cor, exm->num);

  printf("Class        \tRecall                \tPrecision             \tF\n");
  printf("-------------\t----------------------\t----------------------\t-------\n");
  sum_cap = sum_sys = sum_gld = 0;
  sum_r = sum_p = sum_f = 0.0;
  for (i = 0; i < mcmdl->class; i++) {
    double r, p, f;
    r = (gld[i] > 0.0) ? (double)cap[i] / gld[i] : 0.0;
    p = (sys[i] > 0.0) ? (double)cap[i] / sys[i] : 0.0;
    f = (p + r > 0.0) ? 2.0 * p * r / (p + r) : 0.0;
    printf("%13d\t%6.2f%%(%6d/%6d)\t%6.2f%%(%6d/%6d)\t%6.2f%%\n", i, r * 100.0, cap[i], gld[i], p * 100.0, cap[i], sys[i], f * 100.0);
    sum_cap += cap[i];
    sum_sys += sys[i];
    sum_gld += gld[i];
    sum_r += r;
    sum_p += p;
    sum_f += f;
  }

  printf("-------------\t----------------------\t----------------------\t-------\n");
  /* Macro: Weighs equally all classes, Micro: Weights equally all documents */
  r_mac = sum_r / mcmdl->class;
  p_mac = sum_p / mcmdl->class;
  f_mac = sum_f / mcmdl->class;
  r_mic = (sum_gld > 0.0) ? (double)sum_cap / sum_gld : 0.0;
  p_mic = (sum_sys > 0.0) ? (double)sum_cap / sum_sys : 0.0;
  f_mic = (p_mic + r_mic > 0.0) ? 2.0 * p_mic * r_mic / (p_mic + r_mic) : 0.0;
  printf("Macro average\t%6.2f%%(     -/     -)\t%6.2f%%(     -/     -)\t%6.2f%%\n", r_mac * 100.0, p_mac * 100.0, f_mac * 100.0);
  printf("Micro average\t%6.2f%%(%6d/%6d)\t%6.2f%%(%6d/%6d)\t%6.2f%%\n", r_mic * 100.0, sum_cap, sum_gld, p_mic * 100.0, sum_cap, sum_sys, f_mic * 100.0);

  return 0;
}
