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

/*
  A Latent Variable Model for Sentiment Classification
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "lsm_common.h"
#include "exception.h"
#include "split.h"
#include "model.h"


#define BUF_MAX (32 * 1024)	/* 入力バッファのサイズ */


/*
  main
*/
int main(int argc, char **argv) {
  int i, c, d;
  char *mdlfile;
  FILE *fp;
  MDL *mdl;
  int pol;
  XPR xpr;
  double prb;
  double *prb1, *prb2;
  double *pot1, *pot2;
  VAR *v;
  FAC *f;
  int *f1, *f2, f1_num, f2_num, f1_size, f2_size;

  /* オプションの処理 */
  if (argc != 2) {
    fprintf(stderr, "usage: %s <model file> < <data file>\n", argv[0]);
    return 1;
  }
  mdlfile = argv[1];

  /* モデル読み込み */
  fprintf(stderr, "# Reading the model data... ");
  fp = fopen(mdlfile, "rt");
  exception(fp == NULL, "cannot open the model file");
  mdl = mdl_read(fp);
  exception(mdl == NULL, "cannot read the model file");
  fclose(fp);
  fprintf(stderr, "done.\n");

  /* 初期化 */
  xpr.buf = smalloc(sizeof(char) * BUF_MAX);
  xpr.buf_size = BUF_MAX;
  prb1 = smalloc(sizeof(double) * TKN_MAX * CLS_MAX);
  prb2 = smalloc(sizeof(double) * TKN_MAX * CLS_MAX * CLS_MAX);
  v = smalloc(sizeof(VAR) * TKN_MAX);
  f = smalloc(sizeof(FAC) * 2 * TKN_MAX);
  f1_size = 0;
  f1 = NULL;
  f2_size = 0;
  f2 = NULL;
  pot1 = smalloc(sizeof(double) * TKN_MAX * CLS_MAX);
  pot2 = smalloc(sizeof(double) * TKN_MAX * CLS_MAX * CLS_MAX);

  /* 解析 */
  for (; ; ) {
    /* 評価表現読み込み */
    if (readxpr(&xpr, stdin)) break;
    xpr.lbl = 0;	/* 安全のため */

    /* 素性ベクトルの作成 */
    f1_num = 0;
    f2_num = 0;
    for (i = 1; i < xpr.num; i++) {
      for (c = 0; c < CLS_MAX; c++) {
	while (f1_num + BUF_MAX > f1_size) {
	  f1_size = 2 * f1_size + 1;
	  f1 = srealloc(f1, sizeof(int) * f1_size);
	}
	makeftr1(mdl->ft, 0, &xpr, i, c, f1_size, &f1_num, f1);	/* unigram素性 */
	for (d = 0; d < CLS_MAX; d++) {
	  while (f2_num + BUF_MAX > f2_size) {
	    f2_size = 2 * f2_size + 1;
	    f2 = srealloc(f2, sizeof(int) * f2_size);
	  }
	  makeftr2(mdl->ft, 0, &xpr, i, xpr.head[i], c, d, f2_size, &f2_num, f2);
	}
      }
    }

    /* ポテンシャルの初期化 */
    f1_num = 0;
    f2_num = 0;
    for (c = 0; c < CLS_MAX; c++) POT1(pot1, 0, c) = 0.0;
    for (i = 1; i < xpr.num; i++) {
      double tmp;
      for (c = 0; c < CLS_MAX; c++) {
	tmp = 0.0;
	while (f1[f1_num] != -2) {
	  if (f1[f1_num] == -1) {
	    f1_num++;
	    continue;
	  }
	  tmp += mdl->lmd[f1[f1_num++]];
	}
	f1_num++;
	POT1(pot1, i, c) = tmp;
	for (d = 0; d < CLS_MAX; d++) {
	  tmp = 0.0;
	  while (f2[f2_num] != -2) {
	    if (f2[f2_num] == -1) {
	      f2_num++;
	      continue;
	    }
	    tmp += mdl->lmd[f2[f2_num++]];
	  }
	  f2_num++;
	  POT2(pot2, i, c, d) = tmp;
	}
      }
    }
    /* potentialの表示 */
#if 0
    {
      fprintf(stderr, "# potential(node)\n");
      for (i = 1; i < xpr.num; i++) {
	fprintf(stderr, "%d: ", i);
	for (c = 0; c < CLS_MAX; c++) {
	  fprintf(stderr, "%f, ", POT1(pot1, i, c));
	}
	fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
      fprintf(stderr, "# potential(edge)\n");
      for (i = 1; i < xpr.num; i++) {
	fprintf(stderr, "%d: ", i);
	for (c = 0; c < CLS_MAX; c++) {
	  for (d = 0; d < CLS_MAX; d++) {
	    fprintf(stderr, "(%d,%d)=%f, ", c, d, POT2(pot2, i, c, d));
	  }
	}
	fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
    }
#endif

    /* BP */
    bp(&xpr, pot1, pot2, v, f, prb1, prb2);
    prb = 0.0;
    for (c = 0; c < CLS_MAX / 2; c++) prb += PRB1(prb1, 0, c);
    pol = (prb >= 0.5-1.0e-10) ? +1 : -1;

    /* 結果表示 */
#if 0
    {
      int i;
      fprintf(stderr, "!%d:%d:%d\n", (xpr.lbl * pol > 0), xpr.lbl, pol);
      for (i = 0; i < xpr.num; i++) {
	fprintf(stderr, "%d:%d:%s:%d:%d : ", i, xpr.head[i], xpr.surf[i], xpr.pol[i], xpr.rev[i]);
	for (c = 0; c < CLS_MAX; c++) {
	  fprintf(stderr, "%f, ", PRB1(prb1, i, c));
	}
	fprintf(stderr, "\n");
      }
      fprintf(stderr, "\n");
    }
#endif
#if 0
    {
      int i;
      for (i = 1; i < xpr.num; i++) {
	if (xpr.rev[xpr.head[i]] == 1 && PRB1(prb1, i, 0) < PRB1(prb1, i, 1) && PRB1(prb1, xpr.head[i], 0) < PRB1(prb1, xpr.head[i], 1)) fprintf(stderr, "@@ %d\n", i);
      }
    }
#endif

    /* 結果の出力 */
    printf("%+d\n", pol);
  }

  return 0;
}
